为了支持只接受特定数量项目(5项)的API,我想将LINQ结果转换为总是包含设定数量项目的较小项目组。
假设列表{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
我想获得三个较小的列表,每个最多包含5个项目
{1, 2, 3, 4, 5}
{6, 7, 8, 9, 10}
{11, 12, 13, 14, 15}
{16, 17, 18}
如何使用LINQ做到这一点?我假设它涉及Group
或Aggregate
,但我无法确定如何编写它。
答案 0 :(得分:17)
尝试这样的事情:
var result = items.Select((value, index) => new { Index = index, Value = value})
.GroupBy(x => x.Index / 5)
.Select(g => g.Select(x => x.Value).ToList())
.ToList();
它的工作原理是根据原始列表中的索引将项目分组。
答案 1 :(得分:14)
我会做这样的事情:
public static IEnumerable<IEnumerable<T>> TakeChunks<T>(this IEnumerable<T> source, int size)
{
// Typically you'd put argument validation in the method call and then
// implement it using a private method... I'll leave that to your
// imagination.
var list = new List<T>(size);
foreach (T item in source)
{
list.Add(item);
if (list.Count == size)
{
List<T> chunk = list;
list = new List<T>(size);
yield return chunk;
}
}
if (list.Count > 0)
{
yield return list;
}
}
用法:
var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (var chunk in list.TakeChunks(3))
{
Console.WriteLine(string.Join(", ", chunk));
}
输出:
1, 2, 3 4, 5, 6 7, 8, 9 10
理由:
与其他方法(如Skip
和Take
的多次调用或大型LINQ查询相比,以上是:
答案 2 :(得分:4)
一种简单的可能性是使用Enumerable.Skip
和Enumerable.Take
方法,例如:
List<int> nums = new List<int>(){1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
var list1 = nums.Take(5);
var list2 = nums.Skip(5).Take(5);
var list3 = nums.Skip(10).Take(5);
var list4 = nums.Skip(15).Take(5);
正如Jon在评论中提到的,像这样的简单方法每次都会重新评估nums
(在此示例中),这将影响性能(取决于集合的大小)。
答案 3 :(得分:1)
我们在Batch
中有一个MoreLINQ方法。你需要小心如何使用它,因为每次传递给选择器的批处理是对同一个数组的引用 - 但它确实有效。
您可以使用GroupBy
,但这不能是懒惰的 - 它必须在结果之前累积所有才能返回任何内容。这对你来说可能没问题,但值得注意。
答案 4 :(得分:0)
var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
var result = new List<List<int>>();
while (list.Count != 0) {
result.Add(list.TakeWhile(x => x++ <= 5).ToList());
list.RemoveRange(0, list.Count < 5 ? list.Count : 5);
}