Подтвердить что ты не робот

Добавление/конкатенация двух последовательностей IEnumerable

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

4b9b3361

Ответ 1

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

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

Естественно поиск существующих решений в Google/StackOverflow, однако не нашел ничего, что не оценило перечислимое, например. конвертировать в массив, затем использовать Array.Copy() и т.д., поэтому я написал метод расширения и статического utiltiy под названием 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;
    }
}

Ответ 3

Метод 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();
}

Ответ 4

Задержка вызова второго и последующих перечислимых элементов

Я обычно использую Linq IEnumerable<T>.Concat(), но сегодня мне нужно было на 100% быть уверенным, что второе перечисление не было перечислено, пока первое не было обработано до конца. (например, два запроса базы данных, которые я не хотел выполнять одновременно). Таким образом, следующая функция позволила задержать перечисления.

    IEnumerable<T> DelayedConcat<T>(params Func<IEnumerable<T>>[] enumerableList)
    {
        foreach(var enumerable in enumerableList)
        {
            foreach (var item in enumerable())
            {
                yield return item;
            }
        }
    }

Использование:

    return DelayedConcat(
                () => GetEnumerable1(),
                () => GetEnumerable2(),
 // and so on.. () => GetEnumerable3(),
                );

В этом примере вызов функции GetEnumerable2 будет отложен до тех пор, пока GetEnumerable1 не будет перечислен до конца.