Добавление / объединение двух последовательностей IEnumerable - PullRequest
43 голосов
/ 10 февраля 2011

У меня есть два набора датаров.Они все IEnumerable.Я хочу добавить / объединить эти два списка в один список.Я уверен, что это выполнимо.Я не хочу делать цикл for и заметил, что в двух списках есть метод Union и метод Join.Есть идеи?

Ответы [ 3 ]

89 голосов
/ 10 февраля 2011

Предполагая, что ваши объекты относятся к одному типу, вы можете использовать Union или Concat. Обратите внимание, что, подобно ключевому слову SQL UNION, операция Union обеспечит удаление дубликатов, тогда как Concat (например, UNION ALL) просто добавит второй список в конец первого.

IEnumerable<T> first = ...;
IEnumerable<T> second = ...;

IEnumerable<T> combined = first.Concat(second);

или

IEnumerable<T> combined = first.Union(second);

Если они разных типов, вам придется Select сделать их общими. Например:

IEnumerable<TOne> first = ...;
IEnumerable<TTwo> second = ...;

IEnumerable<T> combined = first.Select(f => ConvertToT(f)).Concat(
                          second.Select(s => ConvertToT(s)));

Где ConvertToT(TOne f) и ConvertToT(TTwo s) представляют операцию, которая каким-то образом преобразует экземпляр TOneTTwo соответственно) в экземпляр T.

2 голосов
/ 09 марта 2012

Я только что столкнулся с похожей ситуацией, когда мне нужно объединить несколько последовательностей.

Естественно искал существующие решения в Google / StackOverflow, однако не нашел ничего, что не оценивало перечисляемое, например, преобразовал в массив, затем использовал Array.Copy() и т. Д., Поэтому я написал метод расширения и статической утилизацииConcatMultiple.

Надеюсь, это поможет любому, кто должен сделать то же самое.

/// <summary>
/// Concatenates multiple sequences
/// </summary>
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam>
/// <param name="first">The first sequence to concatenate.</param>
/// <param name="source">The other sequences to concatenate.</param>
/// <returns></returns>
public static IEnumerable<TSource> ConcatMultiple<TSource>(this IEnumerable<TSource> first, params IEnumerable<TSource>[] source)
{
    if (first == null)
        throw new ArgumentNullException("first");

    if (source.Any(x => (x == null)))
        throw new ArgumentNullException("source");

    return ConcatIterator<TSource>(source);
}

private static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, params IEnumerable<TSource>[] source)
{
    foreach (var iteratorVariable in first)
        yield return iteratorVariable;

    foreach (var enumerable in source)
    {
        foreach (var iteratorVariable in enumerable)
            yield return iteratorVariable;
    }
}

/// <summary>
/// Concatenates multiple sequences
/// </summary>
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam>        
/// <param name="source">The sequences to concatenate.</param>
/// <returns></returns>
public static IEnumerable<TSource> ConcatMultiple<TSource>(params IEnumerable<TSource>[] source)
{
    if (source.Any(x => (x == null)))
        throw new ArgumentNullException("source");

    return ConcatIterator<TSource>(source);
}

private static IEnumerable<TSource> ConcatIterator<TSource>(params IEnumerable<TSource>[] source)
{
    foreach (var enumerable in source)
    {
        foreach (var iteratorVariable in enumerable)
            yield return iteratorVariable;
    }
}
1 голос
/ 28 ноября 2015

Метод Join подобен SQL-соединению, в котором список имеет перекрестные ссылки на основе условия, он не является конкатенацией строк или добавлением в список.Метод Union делает то, что вы хотите, так же как и метод Concat , но оба они являются LAZY-оценками и требуют, чтобы параметры были ненулевыми.Они возвращают либо ConcatIterator, либо UnionIterator, и при повторном вызове это может вызвать проблемы .Стремительная оценка приводит к другому поведению, если это то, что вам нужно, то можно использовать метод расширения, подобный приведенному ниже.

public static IEnumerable<T> myEagerConcat<T>(this IEnumerable<T> first,
                                                   IEnumerable<T> second)
{
    return (first ?? Enumerable.Empty<T>()).Concat(
           (second ?? Enumerable.Empty<T>())).ToList();
}
...