使用 LINQ 将一个列表转换为列表的列表

4

我有一个值列表:

IList<V> values = { V1, V2, V3, V4, V5, V6, V7 };

我希望将列表转换为子列表的列表,其中每个子列表的大小是指定的。每个子列表的大小可能会有所不同。例如:
IList<IList<V>> values_size2 = { { V1, V2 }, { V3, V4 }, { V5, V6 }, { V7 } };
IList<IList<V>> values_size3 = { { V1, V2, V3 }, { V4, V5, V6 }, { V7 } };
IList<IList<V>> values_size4 = { { V1, V2, V3, V4 }, { V5, V6, V7 } };

我可以使用嵌套循环轻松完成此操作,但想知道是否有一种聪明的方法可以使用LINQ来完成?

我的初步想法是以某种方式使用Aggregate方法,但立即想不出任何方法。

谢谢。

4个回答

6
这是一个基于IEnumerable的通用Batch函数。你只需将返回类型从IEnumerable<IEnumerable<T>>更改为IEnumerable<IList<T>>,无需进行其他更改(因为在我的实现中已经是一个列表)。要将整个结果更改为列表的列表,您需要在结果上调用`ToList`,或进行更复杂的重构。
请注意,严格来说,这不是使用LINQ,而只是创建了一个使用与LINQ常用的样式和模式相同的新方法。
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source
    , int batchSize)
{
    //TODO validate parameters

    List<T> buffer = new List<T>();

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>();
        }
    }
    if (buffer.Count >= 0)
    {
        yield return buffer;
    }
}

1
解决方案很好,有一件事我会改进 - 在创建缓冲区时将缓冲容量设置为批处理大小。 - Sergey Berezovskiy

5
你可以使用MoreLINQ批处理扩展(可从Nuget获取):
IList<IList<V>> values_size2 = values.Batch(2);
IList<IList<V>> values_size3 = values.Batch(3);
IList<IList<V>> values_size4 = values.Batch(4);

您还可以在此处查看源代码。


1
 public static IEnumerable<IEnumerable<T>> Chunks<T>(this IEnumerable<T> source, int chunkSize)
 {
     while (source.Any())
     {
         yield return source.Take(chunkSize);
         source = source.Skip(chunkSize);
     }
 }

我在实际应用中遇到过这个问题,不建议使用。我在一个相当大的数据集(超过100k)上使用它,结果导致我的CPU飙升。我认为这可能与递归的Skip()有关?还是感谢您的回复! - dana

1

使用.NET 6,您可以使用新的Chunk Linq方法

List<IList<V>> values_size2 = values.Chunk(2).ToList();
List<IList<V>> values_size3 = values.Chunk(3).ToList();
List<IList<V>> values_size4 = values.Chunk(4).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接