0

等しいサブセットをバッチ処理しようとしていIEnumerable<T>ますが、次の解決策に出くわしました:

  1. MoreLinq Nuget ライブラリ バッチ。その実装の詳細は次のとおりです。

    MoreLinq - バッチ、下にソース コードを貼り付けます。

    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);
    }
    }
    
  2. 別の最適なソリューションは、次のリンクで利用できます (メモリ効率が向上します)。

    IEnumerable バッチ処理、下にソース コードを貼り付けます。

    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()でも、2 番目のメソッドでメモリ ストリームをまだ処理しており、メモリが割り当てられていないため、これはエラーになりますが、結果が正しくないことはありません。任意のビュー / 提案

4

1 に答える 1