【问题标题】:splitting a list into multiple lists in C#在 C# 中将一个列表拆分为多个列表
【发布时间】:2011-05-05 12:12:21
【问题描述】:

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

【问题讨论】:

    标签: list c#-4.0


    【解决方案1】:

    一些相关阅读:

    否则,accepted answer 的细微变化可用于枚举(用于延迟加载和处理,以防列表很大/昂贵)。我会注意到具体化每个块/段(例如,通过.ToList.ToArray,或简单地枚举每个块)可能会产生副作用——参见测试。

    方法

    // 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);
    }
    

    测试(Linqpad)

    (注意:我必须为 linqpad 包含 Assert 方法)

    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");
    }
    

    【讨论】:

    【解决方案2】:
    /// <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;
    }
    

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

    【讨论】:

    • 你的方法太棒了!它完全符合我的要求。
    【解决方案3】:

    您可以设置一个List&lt;IEnumerable&lt;string&gt;&gt;,然后使用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)); 
    }
    

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

    【讨论】:

    • 我投了赞成票,因为这正是我所需要的。 RPM1984 也给出了一个很好的答案,但这个答案直接适合我的代码。
    • 如果我需要将列表拆分为 5 个列表,无论这些列表最终会包含多少个字符串,该怎么办?
    猜你喜欢
    • 1970-01-01
    • 2018-11-25
    • 2019-06-05
    • 2022-01-18
    • 1970-01-01
    • 2011-11-13
    • 2019-03-14
    • 2010-09-27
    • 1970-01-01
    相关资源
    最近更新 更多