Элегантный способ объединить несколько коллекций элементов?



скажем, у меня есть произвольное количество коллекций, каждая из которых содержит объекты одного типа (например, 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, но, возможно, нет.

670   10  

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

    Ничего не найдено.