我需要一个优雅的方法,它采用一个可枚举的方法,并获取可枚举的枚举数,每个元素包含相同数量的元素,但最后一个:
public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, Int32 chunkSize)
{
// TODO: code that chunks
}
这就是我的尝试:
public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, Int32 chunkSize)
{
var count = values.Count();
var numberOfFullChunks = count / chunkSize;
var lastChunkSize = count % chunkSize;
for (var chunkIndex = 0; chunkSize < numberOfFullChunks; chunkSize++)
{
yield return values.Skip(chunkSize * chunkIndex).Take(chunkSize);
}
if (lastChunkSize > 0)
{
yield return values.Skip(chunkSize * count).Take(lastChunkSize);
}
}
更新 刚刚发现有一个关于拆分列表Split List into Sublists with LINQ
的类似主题答案 0 :(得分:16)
如果内存消耗不是问题,那么这样吗?
static class Ex
{
public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(
this IEnumerable<TValue> values,
Int32 chunkSize)
{
return values
.Select((v, i) => new {v, groupIndex = i / chunkSize})
.GroupBy(x => x.groupIndex)
.Select(g => g.Select(x => x.v));
}
}
否则,您可以使用yield
关键字获得广告,例如:
static class Ex
{
public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(
this IEnumerable<TValue> values,
Int32 chunkSize)
{
using(var enumerator = values.GetEnumerator())
{
while(enumerator.MoveNext())
{
yield return GetChunk(enumerator, chunkSize).ToList();
}
}
}
private static IEnumerable<T> GetChunk<T>(
IEnumerator<T> enumerator,
int chunkSize)
{
do{
yield return enumerator.Current;
}while(--chunkSize > 0 && enumerator.MoveNext());
}
}
答案 1 :(得分:8)
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
while (source.Any())
{
yield return source.Take(chunksize);
source = source.Skip(chunksize);
}
}
答案 2 :(得分:1)
只进行了一些快速测试,但这似乎有效:
public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, Int32 chunkSize)
{
var valuesList = values.ToList();
var count = valuesList.Count();
for (var i = 0; i < (count / chunkSize) + (count % chunkSize == 0 ? 0 : 1); i++)
{
yield return valuesList.Skip(i * chunkSize).Take(chunkSize);
}
}