2017-03-26 1 views
0

Je suis en train de lots de la IEnumerable<T> dans des sous-ensembles égaux et est tombé sur des solutions suivantes:différence de traitement par lots IEnumerable valeur Count()

  1. MoreLinq bibliothèque Nuget lots, dont la mise en œuvre est détaillée ici:

    MoreLinq - Batch , coller le code source sous:

    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. Une autre solution optimale est disponible sur le suivant l encre (plus efficace de la mémoire):

    IEnumerable Batching, coller le code source sous:

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

Les deux solutions fournissent le résultat final comme IEnumerable<IEnumerable<T>>.

je trouve la différence dans le morceau de code suivant:

var result = Fetch IEnumerable<IEnumerable<T>> de méthode soit suggérée ci-dessus

result.Count(), conduit à un résultat différent, son correct pour MoreLinq lot, mais pas correct pour un autre, même lorsque le résultat est correct et même pour les deux

Prenons l'exemple follwing:

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 

Même lorsque le résultat de traitement par lots fourni est correct, lorsque nous faisons ToList(), est l'erreur puisque nous traitons toujours le flux de mémoire dans la deuxième méthode et la mémoire n'est pas allouée, mais le résultat incorrect ne sera pas le cas, suggestions

+1

Je pense que vous devez partager le code que vous exécutez. – buffjape

+0

Si vous regardez la question attentivement, le code est là, jusqu'à et sauf si vous préférez copier le code source des liens respectifs aussi. Quelle partie pensez-vous est manquant/pas clair, les deux mécanismes de traitement par lots sont extensions IEnumerable –

+0

@Veverke Aucun lot fonctionne, c'est la partie intéressante, comme je l'ai mentionné, il montre le résultat correct sur faire ToList() ', mais' Count () 'n'est pas correct. Aussi le code incorrect est la réponse à la question de dépassement de pile, non liée à MoreLinq, je préfère cette réponse en raison de son optimisation mais je ne peux pas indiquer la raison du problème –

Répondre

1

La raison pour laquelle deuxième résultat retour Count = 10 est parce qu'il utilise while (enumerator.MoveNext()) qui produira 10 fois et provoque résultant dénombrable contenir 10 enumerables au lieu de 3.

réponse avec un score plus élevé https://stackoverflow.com/a/13731854/2138959 en question fait référence à condition raisonnable solution au problème aussi bien.

+0

Comme indiqué dans la réponse référencée, il n'est pas idéal car il détruit l'évaluation paresseuse à GroupBy –

+0

Oui, c'est vrai. –