我有一个值列表:
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方法,但不会马上想到任何事情。
感谢。
答案 0 :(得分: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 :(得分: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);
您还可以查看来源here。
答案 2 :(得分:1)
在 .NET 6 中,您可以使用 new Chunk
Linq method
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();
答案 3 :(得分:0)
鉴于其他人的答案,我使用纯LINQ提出了我自己的解决方案,如下所示:
IList<IList<T>> Batch<T>(IList<T> values, int batchSize)
{
return values.Aggregate(
new List<IList<T>>(),
(state, next) => {
IList<T> batch = (state.Count > 0) ? state[state.Count - 1] : null;
if ((batch == null) || (batch.Count == batchSize))
{
batch = new List<T>(batchSize);
state.Add(batch);
}
batch.Add(next);
return state;
});
}
这可能没有使用IEnumerable那么高效,但在我的情况下我处理的是小集,所以它应该没关系。
我将选择Servy的答案作为“正确的”答案,因为它不依赖于外部库并引导我使用我的解决方案。
感谢大家的帮助:)
答案 4 :(得分:0)
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);
}
}