124 votes

Une façon élégante de combiner plusieurs collections d'éléments ?

Supposons que je dispose d'un nombre arbitraire de collections, chacune contenant des objets du même type (par exemple, List<int> foo y List<int> bar ). Si ces collections étaient elles-mêmes dans une collection (par exemple, de type List<List<int>> Je pourrais utiliser SelectMany pour les réunir en une seule collection.

Cependant, si ces collections ne sont pas déjà dans la même collection, j'ai l'impression que je devrais écrire une méthode comme celle-ci :

public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
   return toCombine.SelectMany(x => x);
}

Que j'appellerais alors ainsi :

var combined = Combine(foo, bar);

Existe-t-il un moyen propre et élégant de combiner (un nombre quelconque de) collections sans avoir à écrire une méthode utilitaire telle que Combine ci-dessus ? Cela semble suffisamment simple pour qu'il y ait un moyen de le faire dans LINQ, mais ce n'est peut-être pas le cas.

136voto

Domenic Points 40761

Je pense que vous cherchez peut-être l'outil LINQ .Concat() ?

var combined = foo.Concat(bar).Concat(foobar).Concat(...);

Alternativement, .Union() supprimera les éléments en double.

42voto

nawfal Points 13500

Pour moi Concat comme méthode d'extension n'est pas très élégante dans mon code lorsque j'ai plusieurs grandes séquences à concaténer. Il s'agit simplement d'un problème d'indentation/de formatage du code et de quelque chose de très personnel.

Bien sûr, ça a l'air bien comme ça :

var list = list1.Concat(list2).Concat(list3);

Ce n'est pas si facile à lire quand cela se présente comme suit :

var list = list1.Select(x = > x)
   .Concat(list2.Where(x => true)
   .Concat(list3.OrderBy(x => x));

Ou quand il ressemble à.. :

return Normalize(list1, a, b)
    .Concat(Normalize(list2, b, c))
       .Concat(Normalize(list3, c, d));

ou tout autre format préféré. Les choses empirent avec des concaténations plus complexes. La raison de mon en quelque sorte La dissonance cognitive avec le style ci-dessus est que la première séquence se situe en dehors de l'espace de travail. Concat alors que les séquences suivantes se trouvent à l'intérieur. Je préfère appeler la méthode statique Concat directement et non le style d'extension :

var list = Enumerable.Concat(list1.Select(x => x),
                             list2.Where(x => true));

Pour un plus grand nombre de séquences concaténées, j'utilise la même méthode statique que dans l'OP :

public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
    return sequences.SelectMany(x => x);
}

Je peux donc écrire :

return EnumerableEx.Concat
(
    list1.Select(x = > x),
    list2.Where(x => true),
    list3.OrderBy(x => x)
);

Il a l'air mieux. Le nom de classe supplémentaire, autrement redondant, que je dois écrire n'est pas un problème pour moi, étant donné que mes séquences ont l'air plus propres avec l'élément Concat appel. C'est moins un problème en C# 6 . Vous pouvez simplement écrire :

return Concat(list1.Select(x = > x),
              list2.Where(x => true),
              list3.OrderBy(x => x));

On aurait aimé avoir des opérateurs de concaténation de listes en C#, quelque chose comme :

list1 @ list2 // F#
list1 ++ list2 // Scala

C'est beaucoup plus propre.

34voto

astreltsov Points 1275

Dans le cas où vous do ont une collection de collections, c'est-à-dire un List<List<T>> , Enumerable.Aggregate est une façon plus élégante de combiner toutes les listes en une seule :

var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });

14voto

Jason Points 125291

Utilice Enumerable.Concat comme suit :

var combined = foo.Concat(bar).Concat(baz)....;

13voto

drs Points 121

Vous pouvez toujours utiliser Aggregate combiné à Concat...

        var listOfLists = new List<List<int>>
        {
            new List<int> {1, 2, 3, 4},
            new List<int> {5, 6, 7, 8},
            new List<int> {9, 10}
        };

        IEnumerable<int> combined = new List<int>();
        combined = listOfLists.Aggregate(combined, (current, list) => current.Concat(list)).ToList();

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