list C#将一个列表拆分为多个列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4104536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 01:34:03  来源:igfitidea点击:

splitting a list into multiple lists in C#

listc#-4.0

提问by Retrocoder

I have a list of strings which I send to a queue. I need to split up the list so that I end up with a list of lists where each list contains a maximum (user defined) number of strings. So for example, if I have a list with the following A,B,C,D,E,F,G,H,I and the max size of a list is 4, I want to end up with a list of lists where the first list item contains: A,B,C,D, the second list has: E,F,G,H and the last list item just contains: I. I have looked at the “TakeWhile” function but am not sure if this is the best approach. Any solution for this?

我有一个发送到队列的字符串列表。我需要拆分列表,以便最终得到一个列表列表,其中每个列表包含最大(用户定义的)字符串数。例如,如果我有一个包含以下 A、B、C、D、E、F、G、H、I 的列表,并且列表的最大大小为 4,我想最终得到一个列表列表,其中第一个列表项包含:A、B、C、D,第二个列表包含:E、F、G、H,最后一个列表项仅包含:I。我看过“TakeWhile”函数,但不确定是否这是最好的方法。有什么解决办法吗?

回答by Fredrik M?rk

You can set up a List<IEnumerable<string>>and then use Skipand Taketo split the list:

您可以设置一个List<IEnumerable<string>>然后使用SkipTake来拆分列表:

IEnumerable<string> allStrings = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };

List<IEnumerable<string>> listOfLists = new List<IEnumerable<string>>();
for (int i = 0; i < allStrings.Count(); i += 4)
{                
    listOfLists.Add(allStrings.Skip(i).Take(4)); 
}

Now listOfListswill contain, well, a list of lists.

现在listOfLists将包含一个列表列表。

回答by RPM1984

/// <summary>
/// Splits a <see cref="List{T}"/> into multiple chunks.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">The list to be chunked.</param>
/// <param name="chunkSize">The size of each chunk.</param>
/// <returns>A list of chunks.</returns>
public static List<List<T>> SplitIntoChunks<T>(List<T> list, int chunkSize)
{
    if (chunkSize <= 0)
    {
        throw new ArgumentException("chunkSize must be greater than 0.");
    }

    List<List<T>> retVal = new List<List<T>>();
    int index = 0;
    while (index < list.Count)
    {
        int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
        retVal.Add(list.GetRange(index, count));

        index += chunkSize;
    }

    return retVal;
}

Reference: http://www.chinhdo.com/20080515/chunking/

参考:http: //www.chinhdo.com/20080515/chunking/

回答by drzaus

Some related reading:

一些相关阅读:

Otherwise, minor variation on accepted answerto work with enumerables (for lazy-loading and processing, in case the list is big/expensive). I would note that materializing each chunk/segment (e.g. via .ToListor .ToArray, or simply enumerating each chunk) could have sideeffects -- see tests.

否则,使用可枚举的可接受答案的微小变化(用于延迟加载和处理,以防列表很大/昂贵)。我会注意到实现每个块/段(例如通过.ToList.ToArray,或简单地枚举每个块)可能会产生副作用——请参阅测试。

Methods

方法

// so you're not repeatedly counting an enumerable
IEnumerable<IEnumerable<T>> Chunk<T>(IEnumerable<T> list, int totalSize, int chunkSize) {
    int i = 0;
    while(i < totalSize) {
        yield return list.Skip(i).Take(chunkSize);
        i += chunkSize;
    }
}
// convenience for "countable" lists
IEnumerable<IEnumerable<T>> Chunk<T>(ICollection<T> list, int chunkSize) {
    return Chunk(list, list.Count, chunkSize);
}
IEnumerable<IEnumerable<T>> Chunk<T>(IEnumerable<T> list, int chunkSize) {
    return Chunk(list, list.Count(), chunkSize);
}

Test (Linqpad)

测试 (Linqpad)

(note: I had to include the Assertmethods for linqpad)

(注意:我必须包含Assertlinqpad的方法)

void Main()
{
    var length = 10;
    var size = 4;

    test(10, 4);
    test(10, 6);
    test(10, 2);
    test(10, 1);

    var sideeffects = Enumerable.Range(1, 10).Select(i => {
        string.Format("Side effect on {0}", i).Dump();
        return i;
    });

    "--------------".Dump("Before Chunking");
    var result = Chunk(sideeffects, 4);
    "--------------".Dump("After Chunking");
    result.Dump("SideEffects");
    var list = new List<int>();
    foreach(var segment in result) {
        list.AddRange(segment);
    }
    list.Dump("After crawling");

    var segment3 = result.Last().ToList();
    segment3.Dump("Last Segment");
}

// test
void test(int length, int size) {
    var list = Enumerable.Range(1, length);

    var c1 = Chunk(list, size);

    c1.Dump(string.Format("Results for [{0} into {1}]", length, size));

    Assert.AreEqual( (int) Math.Ceiling( (double)length / (double)size), c1.Count(), "Unexpected number of chunks");
    Assert.IsTrue(c1.All(c => c.Count() <= size), "Unexpected size of chunks");
}