2017-03-26 3 views
0

Ich versuche, die IEnumerable<T> in gleichen Teilmengen zu Charge und kam über folgende Lösungen:IEnumerable batching Diskrepanz in Count() Wert

  1. MoreLinq Nuget Bibliothek Batch, deren Umsetzung detailliert hier:

    MoreLinq - Batch , Einfügen Quellcode unter:

    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. Eine weitere optimale Lösung ist auf der folgenden l verfügbar Tinte (mehr Speicher effizient):

    IEnumerable Batching, code Einfügen Quelle unter:

    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()); 
        } 
    } 
    

Beide Lösungen bieten, die das Endergebnis als IEnumerable<IEnumerable<T>>.

Ich finde die Diskrepanz in der folgenden Code:

var result = Fetch IEnumerable<IEnumerable<T>> aus beiden Verfahren vorgeschlagen oben

result.Count(), führt zu unterschiedlichem Ergebnis seiner korrekten für MoreLinq Batch, aber nicht korrekt für andere, auch wenn das Ergebnis korrekt ist und für beide gleich

das follwing Beispiel vor:

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 

Auch wenn das Batching-Ergebnis korrekt ist, wenn wir ToList() tun, ist der Fehler, da wir immer noch mit dem Speicher-Stream in der zweiten Methode und Speicher nicht zugeordnet ist, aber immer noch falsches Ergebnis nicht der Fall sein wird, Alle Ansichten/Vorschläge

+1

Ich denke, dass Sie den Code teilen müssen, den Sie gerade ausführen. – buffjape

+0

Wenn Sie die Frage sorgfältig betrachten, ist der Code genau da, bis Sie den Quellcode aus den entsprechenden Links kopieren möchten. Was Teil Ihrer Meinung nach fehlt/unklar, beide die Batching-Mechanismen sind IEnumerable Erweiterungen –

+0

@ Veverke Keine Batch-Arbeiten, das ist der interessante Teil, wie ich erwähnt, zeigt das korrekte Ergebnis auf 'ToList()', aber 'Count () 'ist nicht korrekt. Falscher Code ist auch die Stapelüberlauf-Frageantwort, nicht verwandt mit MoreLinq, ich bevorzuge diese Antwort wegen seiner Optimierung aber kann den Grund für das Problem nicht aufzeigen –

Antwort

1

der Grund, warum zweite Ergebnis Rückkehr Count = 10 ist, weil es while (enumerator.MoveNext()) verwendet, die das 10-fache ergeben wird und bewirkt, dass sich ergeb enumerable 10 enumerables statt 3.

Antwort mit einer höheren Punktzahl https://stackoverflow.com/a/13731854/2138959 in referenzierten Frage enthalten angemessene bereitgestellt Lösung für das Problem auch.

+0

Wie in der referenzierten Antwort darauf hingewiesen, ist es nicht ideal, da es die Lazy Evaluation fällig ist zu GroupBy –

+0

Ja, das stimmt. –