我正在尝试在相同的子集中批量IEnumerable<T>
并遇到以下解决方案:
MoreLinq Nuget library Batch,其实现详见:
MoreLinq - Batch,粘贴下面的源代码:
public static IEnumerable<TResult> Batch<TSource, TResult>(this
IEnumerable<TSource> source, int size,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (size <= 0) throw new ArgumentOutOfRangeException(nameof(size));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
return BatchImpl(source, size, resultSelector);
}
private static IEnumerable<TResult> BatchImpl<TSource, TResult> (this IEnumerable<TSource> source, int
size,Func<IEnumerable<TSource>, TResult> resultSelector)
{
Debug.Assert(source != null);
Debug.Assert(size > 0);
Debug.Assert(resultSelector != null);
TSource[] bucket = null;
var count = 0;
foreach (var item in source)
{
if (bucket == null)
{
bucket = new TSource[size];
}
bucket[count++] = item;
// The bucket is fully buffered before it's yielded
if (count != size)
{
continue;
}
// Select is necessary so bucket contents are streamed too
yield return resultSelector(bucket);
bucket = null;
count = 0;
}
// Return the last bucket with all remaining elements
if (bucket != null && count > 0)
{
Array.Resize(ref bucket, count);
yield return resultSelector(bucket);
}
}
以下链接提供了另一种最佳解决方案(内存效率更高):
IEnumerable Batching,粘贴下面的源代码:
public static class BatchLinq
{
public static IEnumerable<IEnumerable<T>> CustomBatch<T>(this IEnumerable<T> source, int size)
{
if (size <= 0)
throw new ArgumentOutOfRangeException("size", "Must be greater than zero.");
using (IEnumerator<T> enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
yield return TakeIEnumerator(enumerator, size);
}
private static IEnumerable<T> TakeIEnumerator<T>(IEnumerator<T> source, int size)
{
int i = 0;
do
yield return source.Current;
while (++i < size && source.MoveNext());
}
}
两种解决方案都将结果提供为IEnumerable<IEnumerable<T>>
。
我发现以下代码中存在差异:
var result = Fetch IEnumerable<IEnumerable<T>>
来自上面建议的任何一种方法
result.Count()
,导致不同的结果,对于MoreLinq Batch是正确的,但对于其他的不正确,即使结果正确且两者都相同
考虑下面的例子:
IEnumerable<int> arr = new int[10] {1,2,3,4,5,6,7,8,9,10};
For a Partition size 3
arr.Batch(3).Count(), will provide result 4 which is correct
arr.BatchLinq(3).Count(), will provide result 10 which is incorrect
即使提供的批处理结果是正确的,当我们执行ToList()
时,是错误,因为我们仍在处理第二种方法中的内存流并且内存未分配,但仍然不正确的结果不应该是这个案子,任何意见/建议
答案 0 :(得分:1)
第二个结果返回Count = 10的原因是因为它使用了while (enumerator.MoveNext())
,它将产生10次并导致结果可枚举包含10个枚举而不是3个。
在引用的问题中以较高的分数https://stackoverflow.com/a/13731854/2138959回答,也为问题提供了合理的解决方案。