Ответ 1
Я думаю, что вы можете искать LINQ .Concat()
?
var combined = foo.Concat(bar).Concat(foobar).Concat(...);
В качестве альтернативы .Union()
удаляет повторяющиеся элементы.
Скажем, у меня есть произвольное количество коллекций, каждый из которых содержит объекты одного типа (например, 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 должен быть способ сделать это, но, возможно, нет.
Я думаю, что вы можете искать LINQ .Concat()
?
var combined = foo.Concat(bar).Concat(foobar).Concat(...);
В качестве альтернативы .Union()
удаляет повторяющиеся элементы.
Для меня Concat
как метод расширения не очень элегантен в моем коде, когда у меня есть несколько больших последовательностей для конкататации. Это просто проблема кода/отступа/форматирования и что-то очень личное.
Конечно, это выглядит так:
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));
или как вы предпочитаете форматирование. Вещи ухудшаются с более сложными конкатами. Причина моего рода когнитивного диссонанса с вышеуказанным стилем заключается в том, что первая последовательность лежит вне метода 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
. Это меньше проблем в С# 6. Вы можете просто написать:
return Concat(list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x));
Хотелось бы, чтобы у нас были операторы конкатенации списков в С#, что-то вроде:
list1 @ list2 // F#
list1 ++ list2 // Scala
Так чище.
Для случая, когда у вас есть коллекция коллекций, то есть List<List<T>>
, Enumerable.Aggregate
- более элегантный способ объединить все списки в один:
var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
Используйте Enumerable.Concat
так:
var combined = foo.Concat(bar).Concat(baz)....;
Используйте Enumerable.Concact
:
var query = foo.Concat(bar);
Вы всегда можете использовать 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();
Единственное, что я вижу, это использовать 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()
будет лучшим выбором, заключается в том, что это будет более очевидно для другого разработчика. Более читабельны и просты.
Вы можете использовать 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
для удаления дубликатов, как указано в других ответах.
Пара методов с использованием инициализаторов коллекций -
при условии, что эти списки:
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
SelectMany
с инициализатором массива (на самом деле это не так уж элегантно для меня, но не зависит от какой-либо вспомогательной функции):
var combined = new []{ list1, list2 }.SelectMany(x => x);
Определите расширение списка для Add, которое разрешает IEnumerable<T>
в List<T>
инициализаторе:
public static class ListExtensions
{
public static void Add<T>(this List<T> list, IEnumerable<T> items) => list.AddRange(items);
}
Затем вы можете создать новый список, содержащий элементы других подобных (это также позволяет смешивать отдельные элементы).
var combined = new List<int> { list1, list2, 7, 8 };