Supposons que j'ai un nombre arbitraire de collections, chacune contenant des objets du même type (par exemple, List<int> foo
et 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 combiner en une seule.
Cependant, si ces collections ne sont pas déjà dans la même collection, j'ai l'impression qu'il me faudrait écrire une méthode comme celle-ci:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
Ce que j'appellerais alors comme ceci:
var combined = Combine(foo, bar);
Existe-t-il un moyen simple et élégant de combiner un nombre quelconque de collections sans avoir à écrire une méthode utilitaire telle que Combine
ci-dessus? Il semble assez simple qu'il y ait un moyen de le faire dans LINQ, mais peut-être pas.
Je pense que vous pourriez être à la recherche de .Concat()
?
var combined = foo.Concat(bar).Concat(foobar).Concat(...);
Sinon, .Union()
supprimera les éléments en double.
Pour moi, Concat
en tant que méthode d'extension n'est pas très élégant dans mon code lorsque j'ai plusieurs séquences volumineuses à concaténer. Il s’agit simplement d’un problème d’indentation/de formatage et de quelque chose de très personnel.
Bien sûr, ça ressemble à ça:
var list = list1.Concat(list2).Concat(list3);
Pas si lisible quand ça se lit comme:
var list = list1.Select(x = > x)
.Concat(list2.Where(x => true)
.Concat(list3.OrderBy(x => x));
Ou quand ça ressemble à:
return Normalize(list1, a, b)
.Concat(Normalize(list2, b, c))
.Concat(Normalize(list3, c, d));
ou quelle que soit votre mise en forme préférée. Les choses s'aggravent avec des concats plus complexes. La raison de ma sorte de dissonance cognitive avec le style ci-dessus est que la première séquence se situe en dehors de la méthode Concat
alors que les séquences suivantes se trouvent à l'intérieur. Je préfère plutôt 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 plus de nombres de séquences de séquences, je porte la même méthode statique que dans OP:
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
return sequences.SelectMany(x => x);
}
Donc je peux écrire:
return EnumerableEx.Concat
(
list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x)
);
Regarde mieux. Le nom de classe supplémentaire, sinon 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’appel Concat
. C’est moins un problème dans C # 6 . Vous pouvez simplement écrire:
return Concat(list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x));
Souhait que nous ayons des opérateurs de concaténation de listes en C #, quelque chose comme:
list1 @ list2 // F#
list1 ++ list2 // Scala
Beaucoup plus propre de cette façon.
Enumerable.Aggregate
est la bonne façon "élégante" de le faire:
var all = lists.Aggregate((acc, list) => { return acc.Concat(list); });
Utilisez Enumerable.Concat
like so:
var combined = foo.Concat(bar).Concat(baz)....;
Utilisez Enumerable.Concact
:
var query = foo.Concat(bar);
Le seul moyen que je vois est d'utiliser Concat()
var foo = new List<int> { 1, 2, 3 };
var bar = new List<int> { 4, 5, 6 };
var tor = new List<int> { 7, 8, 9 };
var result = foo.Concat(bar).Concat(tor);
Mais vous devriez décider de ce qui est mieux:
var result = Combine(foo, bar, tor);
ou
var result = foo.Concat(bar).Concat(tor);
Un point pourquoi Concat()
sera un meilleur choix est que ce sera plus évident pour un autre développeur. Plus lisible et simple.
Vous pouvez toujours utiliser Aggregate combiné avec 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();
Vous pouvez utiliser Union comme suit:
var combined=foo.Union(bar).Union(baz)...
Cela supprimera les éléments identiques, cependant, si vous en avez, vous pouvez utiliser plutôt Concat
.
Étant donné que vous commencez avec un ensemble de collections séparées, je pense que votre solution est plutôt élégante. Vous allez devoir faire quelque chose pour les assembler.
Il serait plus pratique syntaxiquement de créer une méthode d’extension à partir de votre méthode Combiner, afin de la rendre disponible où que vous soyez.
Tout ce dont vous avez besoin est la suivante, pour tout IEnumerable<IEnumerable<T>> lists
:
var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));
Cela combinera tous les éléments de lists
en un IEnumerable<T>
(avec des doublons). Utilisez Union
au lieu de Concat
pour supprimer les doublons, comme indiqué dans les autres réponses.