145 votes

Créer des lots dans linq

Quelqu'un peut-il suggérer un moyen de créer des lots d'une certaine taille en linq ?

Idéalement, je voudrais pouvoir effectuer des opérations par tranches d'une certaine quantité configurable.

146voto

Sergey Berezovskiy Points 102044

Vous n'avez pas besoin d'écrire de code. Utilisez PlusLINQ La méthode Batch, qui permet de regrouper la séquence source en lots de taille variable (MoreLINQ est disponible sous la forme d'un paquet NuGet que vous pouvez installer) :

int size = 10;
var batches = sequence.Batch(size);

Qui est mis en œuvre comme :

public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(
                  this IEnumerable<TSource> source, int size)
{
    TSource[] bucket = null;
    var count = 0;

    foreach (var item in source)
    {
        if (bucket == null)
            bucket = new TSource[size];

        bucket[count++] = item;
        if (count != size)
            continue;

        yield return bucket;

        bucket = null;
        count = 0;
    }

    if (bucket != null && count > 0)
        yield return bucket.Take(count).ToArray();
}

109voto

L.B Points 54001
public static class MyExtensions
{
    public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items,
                                                       int maxItems)
    {
        return items.Select((item, inx) => new { item, inx })
                    .GroupBy(x => x.inx / maxItems)
                    .Select(g => g.Select(x => x.item));
    }
}

et l'usage serait :

List<int> list = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

foreach(var batch in list.Batch(3))
{
    Console.WriteLine(String.Join(",",batch));
}

SORTIE :

0,1,2
3,4,5
6,7,8
9

46voto

Si vous commencez par sequence défini comme un IEnumerable<T> et vous savez qu'il peut être énuméré plusieurs fois en toute sécurité (par exemple, parce qu'il s'agit d'un tableau ou d'une liste), vous pouvez utiliser ce modèle simple pour traiter les éléments par lots :

while (sequence.Any())
{
    var batch = sequence.Take(10);
    sequence = sequence.Skip(10);

    // do whatever you need to do with each batch here
}

39voto

dana Points 4890

Un site Enumerable.Chunk() a été ajoutée à .NET 6.0.

Ejemplo:

var list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };

var chunks = list.Chunk(3);
// returns { { 1, 2, 3 }, { 4, 5, 6 }, { 7 } }

Pour ceux qui ne peuvent pas faire de mise à niveau, la source est disponible sur GitHub .

32voto

infogulch Points 337

Il s'agit d'une implémentation entièrement paresseuse, à faible coût et à fonction unique de Batch qui ne fait pas d'accumulation. Basée sur (et corrigeant les problèmes de) l'implémentation de Nick Whaley. solution avec l'aide d'EricRoller.

L'itération provient directement de l'IEnumerable sous-jacent. Les éléments doivent donc être énumérés dans un ordre strict, et on ne peut y accéder plus d'une fois. Si certains éléments ne sont pas consommés dans une boucle interne, ils sont rejetés (et essayer d'y accéder à nouveau par le biais d'un itérateur sauvegardé lèvera l'interdiction d'accès aux éléments). InvalidOperationException: Enumeration already finished. ).

Vous pouvez tester un échantillon complet à l'adresse suivante .NET Fiddle .

public static class BatchLinq
{
    public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
    {
        if (size <= 0)
            throw new ArgumentOutOfRangeException("size", "Must be greater than zero.");
        using (var enumerator = source.GetEnumerator())
            while (enumerator.MoveNext())
            {
                int i = 0;
                // Batch is a local function closing over `i` and `enumerator` that
                // executes the inner batch enumeration
                IEnumerable<T> Batch()
                {
                    do yield return enumerator.Current;
                    while (++i < size && enumerator.MoveNext());
                }

                yield return Batch();
                while (++i < size && enumerator.MoveNext()); // discard skipped items
            }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X