web-dev-qa-db-ja.com

2つのIEnumerableシーケンスの追加/連結

2行のデータ行があります。これらはそれぞれIEnumerableです。これらの2つのリストを1つのリストに追加/連結します。これは実行可能であると確信しています。 forループを実行したくないので、2つのリストにUnionメソッドとJoinメソッドがあることに気付きました。何か案は?

43
MikeTWebb

オブジェクトが同じタイプであると仮定すると、UnionまたはConcatのいずれかを使用できます。 SQLのUNIONキーワードと同様に、Union操作では重複が確実に排除されますが、Concat(_UNION ALL_など)は2番目のリストを追加するだけです。最初の最後まで。

_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)は、TOne(およびTTwoのインスタンス)をT

89
Adam Robinson

複数のシーケンスを連結する必要がある同様の状況が発生しました。

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;
    }
}
2
Dennis

Join メソッドは、SQLジョインに似ています。リストは条件に基づいて相互参照され、文字列の連結やリストへの追加ではありません。 nion メソッドは、 Concat メソッドと同様に、必要な処理を行いますが、両方ともLAZY評価であり、パラメーターがnullでないという要件があります。これらは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();
}
1
jmoreno

2番目以降の列挙可能オブジェクトの遅延呼び出し

通常、Linq IEnumerable<T>.Concat()を使用しますが、今日は、最初の列挙が最後まで処理されるまで2番目の列挙が列挙されないことを100%確認する必要がありました。 (たとえば、同時に実行したくない2つのdbクエリ)。そのため、次の関数が列挙を遅延させるトリックを作成しました。

    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(),
                );

この例では、GetEnumerable1関数が最後まで列挙されるまで、GetEnumerable2関数の呼び出しが遅れます。

0