Элегантный способ объединить несколько коллекций элементов?
скажем, у меня есть произвольное количество коллекций, каждая из которых содержит объекты одного типа (например, List<int> foo и List<int> bar). Если эти коллекции сами были в коллекции (например, типа List<List<int>>, Я мог бы использовать SelectMany объединить их все в одну коллекцию.
однако, если эти коллекции уже не находятся в одной коллекции, мне кажется, что мне придется написать такой метод:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
который я бы тогда назвал как это:
var combined = Combine(foo, bar);
есть ли чистый, элегантный способ объединить (любое количество) коллекций без необходимости писать служебный метод, такой как Combine выше? Кажется достаточно простым, что должен быть способ сделать это в LINQ, но, возможно, нет.
10 ответов:
Я думаю, вы могли бы искать для LINQ-это
.Concat()?var combined = foo.Concat(bar).Concat(foobar).Concat(...);кроме того,
.Union()удалить повторяющиеся элементы.
для меня
Concatкак метод расширения не очень элегантный в моем коде, когда у меня есть несколько больших последовательностей для конката. Это просто проблема отступа/форматирования codde и что-то очень личное.конечно, это выглядит хорошо, как это:
var list = list1.Concat(list2).Concat(list3);не так читается, когда он читает, как:
var list = list1.Select(x = > x) .Concat(list2.Where(x => true) .Concat(list3.OrderBy(x => x));или когда это выглядит так:
return Normalize(list1, a, b) .Concat(Normalize(list2, b, c)) .Concat(Normalize(list3, c, d));или независимо от предпочтительного форматирования. Еще хуже обстоят дела с более сложными concats. Этот причина для моего вроде когнитивный диссонанс с вышеуказанным стилем заключается в том, что первая последовательность лежит вне
Concatметод, в то время как последующие последовательности лежат внутри. Я скорее предпочитаю называть статическиеConcatметод непосредственно, а не стиль расширения:var list = Enumerable.Concat(list1.Select(x => x), list2.Where(x => true));для большего количества конкат последовательностей я использую тот же статический метод, что и в OP:
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences) { return sequences.SelectMany(x => x); }так что я могу написать:
return EnumerableEx.Concat ( list1.Select(x = > x), list2.Where(x => true), list3.OrderBy(x => x) );выглядит лучше. Дополнительные, в противном случае избыточное, имя класса, которое я должен написать, не является проблемой для меня, учитывая, что мои последовательности выглядят чище с
Concatзвонок. Это меньше проблем в C# 6. Вы можете просто написать:return Concat(list1.Select(x = > x), list2.Where(x => true), list3.OrderBy(x => x));
использовать
Enumerable.Concatвот так:var combined = foo.Concat(bar).Concat(baz)....;
Enumerable.Aggregateэто правильный "элегантный" способ сделать это:var all = lists.Aggregate((acc, list) => { return acc.Concat(list); });
использовать
Enumerable.Concact:var query = foo.Concat(bar);
единственный способ, который я вижу, это использовать
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);но вы должны решить, что лучше:
var result = Combine(foo, bar, tor);или
var result = foo.Concat(bar).Concat(tor);одна точки почему
Concat()будет лучшим выбором это будет более очевидно для другого разработчика. Более читаемый и простой.
вы всегда можете использовать Aggregate в сочетании с 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();
Вы можете использовать Union следующим образом:
var combined=foo.Union(bar).Union(baz)...это удалит идентичные элементы, хотя, так что если у вас есть те, Вы можете использовать
Concat, вместо.
учитывая, что вы начинаете с кучей отдельных коллекций, я думаю, что ваше решение весьма элегантно. Вам придется сделать что-то сшить их вместе.
было бы более удобно синтаксически сделать метод расширения из вашего метода Combine, который сделал бы его доступным в любом месте.
все что вам нужно это, для любого
IEnumerable<IEnumerable<T>> lists:var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));это объединит все элементы в
listsв одномIEnumerable<T>(с дубликатами). ИспользуйтеUnionвместоConcatчтобы удалить дубликаты, как указано в других ответах.
Comments