8

KeyValuePair で結合された要素のインデックスが同じである にマージしたい と がIEnumerable<T>あります。私は IList を使用していないので、マージするアイテムのカウントやインデックスがないことに注意してください。これを達成するにはどうすればよいですか?私はLINQの回答を好みますが、エレガントな方法で仕事を成し遂げるものは何でもうまくいきます.IEnumerable<U>IEnumerable<KeyValuePair<T,U>>

4

10 に答える 10

17

この質問に出くわした人への更新として、.Net 4.0 はこれを MS の ex としてネイティブにサポートしています。

int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };

var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);

ドキュメンテーション:

このメソッドは、最初のシーケンスの各要素を、2 番目のシーケンスの同じインデックスを持つ要素とマージします。シーケンスに同じ数の要素がない場合、メソッドはシーケンスのいずれかの終わりに到達するまでシーケンスをマージします。たとえば、1 つのシーケンスに 3 つの要素があり、もう 1 つのシーケンスに 4 つの要素がある場合、結果のシーケンスには 3 つの要素しかありません。

于 2010-09-23T17:37:40.470 に答える
17

注: .NET 4.0 の時点で、フレームワークには.ZipIEnumerable の拡張メソッドが含まれています。以下は、後世のため、および 4.0 より前の .NET フレームワーク バージョンで使用するために維持されています。

私はこれらの拡張メソッドを使用します:

// From http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> func) {
    if (first == null) 
        throw new ArgumentNullException("first");
    if (second == null) 
        throw new ArgumentNullException("second");
    if (func == null)
        throw new ArgumentNullException("func");
    using (var ie1 = first.GetEnumerator())
    using (var ie2 = second.GetEnumerator())
        while (ie1.MoveNext() && ie2.MoveNext())
            yield return func(ie1.Current, ie2.Current);
}

public static IEnumerable<KeyValuePair<T, R>> Zip<T, R>(this IEnumerable<T> first, IEnumerable<R> second) {
    return first.Zip(second, (f, s) => new KeyValuePair<T, R>(f, s));
}

編集:コメントの後、いくつかのことを明確にして修正する義務があります:

于 2009-03-25T18:44:41.247 に答える
1

nextensionを見てください:

現在実装されているメソッド

IEnumerable

  • ForEachIEnumerableの各要素に対して指定されたアクションを実行します。
  • アイテムを同じサイズのロットにまとめます。
  • スキャンIEnumerable内のアイテムのペアにデリゲートを適用して、リストを作成します。
  • AtLeastは、IEnumerableに少なくとも一定量のアイテムがあることを確認します。
  • AtMostは、IEnumerableに特定の数のアイテムしか存在しないことを確認します。
  • Zip他の2つのリストを1つに結合してリストを作成します。
  • サイクル別のリストを繰り返してリストを作成します。
于 2009-03-25T18:48:06.650 に答える
1

私は-の線に沿って何かを使用します

IEnumerable<KeyValuePair<T,U>> Merge<T,U>(IEnumerable<T> keyCollection, IEnumerable<U> valueCollection)
{
    var keys = keyCollection.GetEnumerator();
    var values = valueCollection.GetEnumerator();
    try
    { 
        keys.Reset();
        values.Reset();

        while (keys.MoveNext() && values.MoveNext())
        {
            yield return new KeyValuePair<T,U>(keys.Current,values.Current);
        }
    }
    finally
    {
        keys.Dispose();
        values.Dispose();
    }
}

これは正しく機能し、後で適切にクリーンアップする必要があります。

于 2009-03-25T18:54:23.610 に答える
1

ここであなたが求めていることをもう少し詳しく考えてください:

「 KeyValuePair で結合された要素のインデックスが同じ」である 2 つの IEnumerables を結合したいが、「結合しようとしている項目のカウントまたはインデックスがない」。

IEnumerables が並べ替えられているか、並べ替えられていないという保証はありません。2 つの IEnumerable オブジェクトの間に相関関係はありません。

于 2009-03-25T18:44:39.217 に答える
0

JaredParには、あなたがやりたいことを可能にするものを含む、たくさんの便利なものが入ったライブラリがあります。Zip

于 2009-03-25T19:06:37.120 に答える
0

MoreLINQでZipメソッドを使用できます。

于 2009-03-25T18:47:38.510 に答える
0

MSDNには、次のカスタムシーケンス演算子の例があります。そして、ウェルボグは正しい。基になるデータにインデックスがない場合、操作が期待どおりに機能するという保証はありません。

于 2009-03-25T18:49:50.517 に答える
0

Alexey Romanov によるFunctional-dotnet プロジェクトからの別の実装:

/// <summary>
/// Takes two sequences and returns a sequence of corresponding pairs. 
/// If one sequence is short, excess elements of the longer sequence are discarded.
/// </summary>
/// <typeparam name="T1">The type of the 1.</typeparam>
/// <typeparam name="T2">The type of the 2.</typeparam>
/// <param name="sequence1">The first sequence.</param>
/// <param name="sequence2">The second sequence.</param>
/// <returns></returns>
public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(
    this IEnumerable<T1> sequence1, IEnumerable<T2> sequence2) {
    using (
        IEnumerator<T1> enumerator1 = sequence1.GetEnumerator())
    using (
        IEnumerator<T2> enumerator2 = sequence2.GetEnumerator()) {
        while (enumerator1.MoveNext() && enumerator2.MoveNext()) {
            yield return
                Pair.New(enumerator1.Current, enumerator2.Current);
        }
    }
    //
    //zip :: [a] -> [b] -> [(a,b)]
    //zip (a:as) (b:bs) = (a,b) : zip as bs
    //zip _      _      = []
}

new (および戻り値の型) に置き換えれば、準備完了ですPair.NewKeyValuePair<T1, T2>

于 2009-03-25T19:18:01.073 に答える
0

テストされていませんが、動作するはずです:

IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> t, IEnumerable<U> u) {
    IEnumerator<T> et = t.GetEnumerator();
    IEnumerator<U> eu = u.GetEnumerator();

    for (;;) {
        bool bt = et.MoveNext();
        bool bu = eu.MoveNext();
        if (bt != bu)
            throw new ArgumentException("Different number of elements in t and u");
        if (!bt)
            break;
        yield return new KeyValuePair<T, U>(et.Current, eu.Current);
    }
}
于 2009-03-25T18:46:20.180 に答える