Pre*_*zel 41 linq partitioning skip take
如何获取List(使用LINQ)并将其分解为每隔8个条目分区原始列表的列表列表?
我想像这样的东西会涉及Skip和/或Take,但我仍然是LINQ的新手.
编辑:使用C#/ .Net 3.5
编辑2:这个问题的措辞不同于其他"重复"问题.虽然问题是相似的,但这个问题的答案是优越的:"接受"的答案都非常可靠(包括yield声明)以及Jon Skeet建议使用MoreLinq(在"其他"问题中不推荐使用).有时复制是好的,因为它们迫使重新检查问题.
Han*_*man 52
使用以下扩展方法将输入分解为子集
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
{
List<T> toReturn = new List<T>(max);
foreach(var item in source)
{
toReturn.Add(item);
if (toReturn.Count == max)
{
yield return toReturn;
toReturn = new List<T>(max);
}
}
if (toReturn.Any())
{
yield return toReturn;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 38
我们在MoreLINQ中使用这样一种方法作为Batch方法:
// As IEnumerable<IEnumerable<T>>
var items = list.Batch(8);
Run Code Online (Sandbox Code Playgroud)
要么
// As IEnumerable<List<T>>
var items = list.Batch(8, seq => seq.ToList());
Run Code Online (Sandbox Code Playgroud)
LBu*_*kin 15
你最好使用像MoreLinq这样的库,但是如果你真的不得不使用"普通LINQ"这样做,你可以使用GroupBy:
var sequence = new[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
var result = sequence.Select((x, i) => new {Group = i/8, Value = x})
.GroupBy(item => item.Group, g => g.Value)
.Select(g => g.Where(x => true));
// result is: { {1,2,3,4,5,6,7,8}, {9,10,11,12,13,14,15,16} }
Run Code Online (Sandbox Code Playgroud)
基本上,我们使用它的版本为Select()消耗的值提供索引,我们将索引除以8以识别每个值所属的组.然后我们通过这个分组键对序列进行分组.最后一个Select只是减少IGrouping<>到一个IEnumerable<IEnumerable<T>>(并且因为IGrouping是一个并不是绝对必要的IEnumerable).
通过8在示例中分解常量并将其替换为指定参数,可以很容易地将其转换为可重用的方法.它不一定是最优雅的解决方案,它不再是一个懒惰的流媒体解决方案......但它确实有效.
您还可以使用迭代器块(yield return)编写自己的扩展方法,这可以提供更好的性能并使用更少的内存GroupBy.这就是Batch()MoreLinq对IIRC的做法.
这根本不是 Linq 最初设计者的初衷,但请检查一下 GroupBy 的误用:
public static IEnumerable<IEnumerable<T>> BatchBy<T>(this IEnumerable<T> items, int batchSize)
{
var count = 0;
return items.GroupBy(x => (count++ / batchSize)).ToList();
}
[TestMethod]
public void BatchBy_breaks_a_list_into_chunks()
{
var values = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var batches = values.BatchBy(3);
batches.Count().ShouldEqual(4);
batches.First().Count().ShouldEqual(3);
batches.Last().Count().ShouldEqual(1);
}
Run Code Online (Sandbox Code Playgroud)
我认为它赢得了这个问题的“高尔夫”奖。这ToList非常重要,因为您希望在尝试对输出执行任何操作之前确保已实际执行分组。如果删除ToList,您会得到一些奇怪的副作用。