C#での辞書のマージ


493

Dictionary<T1,T2>C#で2つ以上の辞書()をマージする最良の方法は何ですか?(LINQのような3.0の機能は問題ありません)。

私は次のようにメソッド署名を考えています:

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);

または

public static Dictionary<TKey,TValue>
                 Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);

編集: JaredParとJon Skeetからクールなソリューションを入手しましたが、私は重複するキーを処理するものを考えていました。衝突が発生した場合、一貫性が保たれている限り、dictにどの値が保存されていてもかまいません。


174
無関係な、しかし、重複したキーを確認することなく、単に2つの辞書をマージするためにお探しの方のために、これはうまく動作します:dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
Benjol

6
@Benjol回答セクションにこれを追加することができます
M.Kumaran

4
ClojureのC#でのマージ:dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)
Bruce

@Benjol:で最初の辞書からのエントリを優先することにより、重複を排除しdictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)ます。
Suncat2000

回答:


321

これは、重複が発生した場合に何をしたいかによります。たとえば、次のようにすることができます。

var result = dictionaries.SelectMany(dict => dict)
                         .ToDictionary(pair => pair.Key, pair => pair.Value);

重複するキーを取得すると、例外がスローされます。

編集:ToLookupを使用すると、キーごとに複数の値を持つルックアップが表示されます。次に、それを辞書に変換できます。

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

これは少し見栄えが悪く、非効率的ですが、コードの観点から見ると、これが最も速い方法です。(私は確かにそれをテストしていません。)

もちろん、独自のToDictionary2拡張メソッドを作成することもできます(より適切な名前を付けますが、今考える必要はありません)。重複するキーを上書き(または無視)するだけで、それほど難しくはありません。(私の心に)重要なビットはSelectManyを使用し、ディクショナリがキーと値のペアの反復をサポートすることを理解することです。


3
最初のディクショナリから値を取得するのではなく、実際に値をマージするには、ジョンスキートの編集済み回答でgroup => group.First()をgroup => group.SelectMany(value => value)に置き換えます。
andreialecu

3
現在、GroupByはToLookupよりも適しているのではないかと思います。ILookupは、IGroupingの上にインデクサー、サイズプロパティ、およびcontainsメソッドを追加するだけだと思います。そのため、少し速くなる必要がありますか?
2013年

2
@toong:正直なところ、どちらでもかまいません。GroupBy実際に使用すると、もう少し効率的になる可能性がありますが、どちらにしても重要であることは疑わしいと思います。
ジョンスキート2013年

1
@Joe:これは、ToDictionaryメソッド呼び出しに比較子を提供することで十分簡単です。ただし、より一般的なケースでは、答えをシンプルにしたいのですが、カスタムコンパレータを必要とするすべての人が関連するオーバーロードを見つけられることを願っています。
Jon Skeet、

1
@Serge:正確な要件で新しい質問をすることをお勧めします。
Jon Skeet、

265

私はそれをこのようにします:

dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));

シンプルで簡単。このブログの投稿によると、基盤となる実装は列挙子ではなくインデックスで要素にアクセスするため、ほとんどのループよりも高速です(この回答を参照)

もちろん、重複がある場合は例外をスローするので、マージする前に確認する必要があります。


169
重複が問題になる場合は、を使用してくださいdictionaryFrom.ToList().ForEach(x => dictionaryTo[x.Key] = x.Value)。このようにして、からdictionaryFromの値は、おそらく存在するキーの値をオーバーライドします。
okrumnow 2012

7
これはループよりも速くなることはまずありません。ToList()が実際にディクショナリをコピーすることになることを忘れています。ただし、コーディングは高速です!;-)
セーレンBoisen

6
これはより高速です。ToList()は実際にはディクショナリをコピーしないため、ディクショナリ内の要素の参照をコピーするだけです。基本的に、リストオブジェクト自体はメモリ内に新しいアドレスを持ち、オブジェクトは同じです!!
GuruC、2015年

4
ブログの記事は消えますがイェーイウェイバックマシン:web.archive.org/web/20150311191313/http://diditwith.net/2006/10/...
CADはやつ

1
うーん、より良いジョンスキートの答え、私は推測します。
Sнаđошƒаӽ

102

これは、複数のキーがある場合は爆発せず(「より右側の」キーが「左側の」キーを置き換える)、多数の辞書をマージでき(必要な場合)、型を保持します(意味のあるデフォルトのパブリックコンストラクターが必要であるという制限付き)。

public static class DictionaryExtensions
{
    // Works in C#3/VS2008:
    // Returns a new dictionary of this ... others merged leftward.
    // Keeps the type of 'this', which must be default-instantiable.
    // Example: 
    //   result = map.MergeLeft(other1, other2, ...)
    public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
        where T : IDictionary<K,V>, new()
    {
        T newMap = new T();
        foreach (IDictionary<K,V> src in
            (new List<IDictionary<K,V>> { me }).Concat(others)) {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K,V> p in src) {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

}

よくやった。これはまさに私が必要としたものでした。ジェネリックの素晴らしい使い方。構文が少し厄介であることに同意しますが、それについてあなたができることは何もありません。
Peter M

2
私はこの解決策が好きでしたが、注意点があります。this T me辞書がを使用して宣言されている場合、new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase)または類似した辞書を作成した場合、結果の辞書は同じ動作を保持しません。
ジョアン・ポルテラ

3
を作成meするとDictionary<K,V>、を実行できるようvar newMap = new Dictionary<TKey, TValue>(me, me.Comparer);になり、余分なT型パラメーターも回避できます。
ANeves 2014年

1
誰かがこの獣の使い方の例を持っていますか?
Tim

1
@Tim:私はANevesによって溶液を添加し、その結果、より家畜獣:)であり、以下の獣のための例を追加
keni

50

簡単な解決策は次のとおりです。

using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
    Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
    var result = new Dictionary<TKey, TValue>();
    foreach (var dict in dictionaries)
        foreach (var x in dict)
            result[x.Key] = x.Value;
    return result;
}

22

以下をお試しください

static Dictionary<TKey, TValue>
    Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> enumerable)
{
    return enumerable.SelectMany(x => x).ToDictionary(x => x.Key, y => y.Value);
}

19
Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);

1
ただ、不思議-だけではないでしょう連合だけで動作しますか?foreach(var kvp in Message.GetAttachments().Union(mMessage.GetImages()))本番コードで使用して、マイナス面があれば教えてください!:)
Mars Robertson

1
@Michal:UnionはIEnumerable<KeyValuePair<TKey, TValue>>、キーと値の等価性によって等価性が定義されるwhere を返します(代替を可能にするオーバーロードがあります)。これはforeachループでは問題ありませんが、これだけで十分ですが、実際に辞書が必要な場合もあります。
ティモシー

15

私はパーティーに非常に遅れており、おそらく何かが足りないかもしれませんが、重複するキーがないか、OPが言うように、「衝突が発生した場合、どの値がdictに保存されるかは問題ではありません。一貫している」とは、これの何が問題になっていますか(D2をD1にマージ)。

foreach (KeyValuePair<string,int> item in D2)
            {
                 D1[item.Key] = item.Value;
            }

単純すぎるようです。単純すぎるかもしれませんが、何か不足しているのではないでしょうか。これは、重複するキーがないことがわかっているコードで使用しています。私はまだテスト中であるので、後で見つけるのではなく、何かを見落としているかどうかを今知りたいです。


4
最もクリーンで読みやすいソリューションの1つであり、他の多くの人が使用するToList()も回避します。
404

15

次は私のために働きます。重複がある場合は、dictAの値を使用します。

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> dictA, IDictionary<TKey, TValue> dictB)
    where TValue : class
{
    return dictA.Keys.Union(dictB.Keys).ToDictionary(k => k, k => dictA.ContainsKey(k) ? dictA[k] : dictB[k]);
}

@EsbenSkovPedersen私がこれに答えたときに私はそれに遭遇したとは思いません(新しいC#dev)
Ethan Reesor

Guidを値として使用するには、 'where TValue:class'を削除する必要がありました
om471987

@ om471987はい、Guidはクラスではなく構造体なので、それは理にかなっています。もともとその節を追加しなかったときに問題があったと思います。なぜその理由を覚えていない。
Ethan Reesor

10

ここに私が使用するヘルパー関数があります:

using System.Collections.Generic;
namespace HelperMethods
{
    public static class MergeDictionaries
    {
        public static void Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (second == null || first == null) return;
            foreach (var item in second) 
                if (!first.ContainsKey(item.Key)) 
                    first.Add(item.Key, item.Value);
        }
    }
}

ここには多くの優れたソリューションがリストされていますが、私はこのソリューションのシンプルさが一番好きです。ただ私の個人的な好み。
jason 2012年

3
if(first == null)ので、このロジックは無用でfirstはないrefと返されません。そして、それはrefインターフェースのインスタンスとして宣言されているのであり得ません。エラーチェックを削除するか、それをクラスインスタンスとして宣言するか、単に(拡張メソッドなしで)新しいディクショナリを返す必要があります。
Grault

@Jesdisciple-あなたの提案に従って問題を削除しました
Andrew Harry

8

オプション1:これは、両方のディクショナリに重複するキーがないことが確実な場合に何をしたいかによって異なります。あなたができるよりも:

var result = dictionary1.Union(dictionary2).ToDictionary(k => k.Key, v => v.Value)

注:辞書で重複するキーを取得すると、エラーがスローされます。

オプション2:重複するキーを使用できる場合は、where句を使用して重複するキーを処理する必要があります。

var result = dictionary1.Union(dictionary2.Where(k => !dictionary1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value)

注:重複したキーは取得されません。重複するキーがある場合は、dictionary1のキーを取得します。

オプション3: ToLookupを使用する場合。次に、キーごとに複数の値を持つことができるルックアップを取得します。そのルックアップを辞書に変換できます:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

6

paramsオーバーロードを追加するのはどうですか?

また、IDictionary最大の柔軟性を得るには、これらを入力する必要があります。

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> dictionaries)
{
    // ...
}

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(params IDictionary<TKey, TValue>[] dictionaries)
{
    return Merge((IEnumerable<TKey, TValue>) dictionaries);
}

4
彼は、DictionaryExtensionsクラスをさらに優れたものにできることに注意して、ここで他の回答に追加しています。おそらく、この質問はwiki、またはgitにチェックインされたクラスになるはずです...。
Chris Moschini、

5

辞書キーの検索と削除はハッシュ演算であるため、パフォーマンスを考慮し、質問の表現が最善の方法であると考えると、以下は完全に有効なアプローチであり、その他は少し複雑すぎるIMHOだと思います。

    public static void MergeOverwrite<T1, T2>(this IDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
    {
        if (newElements == null) return;

        foreach (var e in newElements)
        {
            dictionary.Remove(e.Key); //or if you don't want to overwrite do (if !.Contains()
            dictionary.Add(e);
        }
    }

または、マルチスレッドアプリケーションで作業していて、辞書をスレッドセーフにする必要がある場合は、次のようにする必要があります。

    public static void MergeOverwrite<T1, T2>(this ConcurrentDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
    {
        if (newElements == null || newElements.Count == 0) return;

        foreach (var ne in newElements)
        {
            dictionary.AddOrUpdate(ne.Key, ne.Value, (key, value) => value);
        }
    }

次に、これをラップして、辞書の列挙を処理できるようにします。以来かかわらず、あなたは、〜O(3N)(すべての条件であること完璧)程度を見ている.Add()んだろう、追加の不要なしかし事実上無料、Contains()舞台裏。良くなるとは思いません。

大規模なコレクションに対する追加の操作を制限したいCount場合は、マージする各ディクショナリの合計を合計し、ターゲットディクショナリの容量をそれに設定する必要があります。これにより、後でサイズ変更するコストを回避できます。だから、最終製品はこのようなものです...

    public static IDictionary<T1, T2> MergeAllOverwrite<T1, T2>(IList<IDictionary<T1, T2>> allDictionaries)
    {
        var initSize = allDictionaries.Sum(d => d.Count);
        var resultDictionary = new Dictionary<T1, T2>(initSize);
        allDictionaries.ForEach(resultDictionary.MergeOverwrite);
        return resultDictionary;
    }

私がIList<T>このメソッドを取り込んだことに注意してください...主にを取り込んだ場合IEnumerable<T>、同じセットの複数の列挙に自分自身を開いているため、ディファードLINQからディクショナリのコレクションを取得すると、非常にコストがかかる可能性があります。ステートメント。


4

上記の回答に基づいていますが、Func-parameterを追加して、呼び出し側が重複を処理できるようにします。

public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts, 
                                                           Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
{
    if (resolveDuplicates == null)
        resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());

    return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
                .ToLookup(pair => pair.Key, pair => pair.Value)
                .ToDictionary(group => group.Key, group => resolveDuplicates(group));
}

4

パーティーはもうほとんど死んでいますが、これが私の拡張ライブラリに組み込まれたuser166390の「改良された」バージョンです。一部の詳細は別として、マージされた値を計算するためにデリゲートを追加しました。

/// <summary>
/// Merges a dictionary against an array of other dictionaries.
/// </summary>
/// <typeparam name="TResult">The type of the resulting dictionary.</typeparam>
/// <typeparam name="TKey">The type of the key in the resulting dictionary.</typeparam>
/// <typeparam name="TValue">The type of the value in the resulting dictionary.</typeparam>
/// <param name="source">The source dictionary.</param>
/// <param name="mergeBehavior">A delegate returning the merged value. (Parameters in order: The current key, The current value, The previous value)</param>
/// <param name="mergers">Dictionaries to merge against.</param>
/// <returns>The merged dictionary.</returns>
public static TResult MergeLeft<TResult, TKey, TValue>(
    this TResult source,
    Func<TKey, TValue, TValue, TValue> mergeBehavior,
    params IDictionary<TKey, TValue>[] mergers)
    where TResult : IDictionary<TKey, TValue>, new()
{
    var result = new TResult();
    var sources = new List<IDictionary<TKey, TValue>> { source }
        .Concat(mergers);

    foreach (var kv in sources.SelectMany(src => src))
    {
        TValue previousValue;
        result.TryGetValue(kv.Key, out previousValue);
        result[kv.Key] = mergeBehavior(kv.Key, kv.Value, previousValue);
    }

    return result;
}

2

@Tim:コメントである必要がありますが、コメントではコードを編集できません。

Dictionary<string, string> t1 = new Dictionary<string, string>();
t1.Add("a", "aaa");
Dictionary<string, string> t2 = new Dictionary<string, string>();
t2.Add("b", "bee");
Dictionary<string, string> t3 = new Dictionary<string, string>();
t3.Add("c", "cee");
t3.Add("d", "dee");
t3.Add("b", "bee");
Dictionary<string, string> merged = t1.MergeLeft(t2, t2, t3);

注:@ANevesによる変更を@Andrew Orsichによるソリューションに適用したため、MergeLeftは次のようになります。

public static Dictionary<K, V> MergeLeft<K, V>(this Dictionary<K, V> me, params IDictionary<K, V>[] others)
    {
        var newMap = new Dictionary<K, V>(me, me.Comparer);
        foreach (IDictionary<K, V> src in
            (new List<IDictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

私が書いたものに近い。これは、ofc Dictionary型に対してのみ機能します。オーバーロードは、他の辞書の種類(のために追加することができConcurrentDictionaryReadOnlyDictionary私は新しいリストの作成を考えていない、など)、およびCONCATは個人的に必要です。最初にparams配列を繰り返し、次に各辞書の各KVPを繰り返しました。ドローバックは見られません。
クラッシュ

辞書の代わりにIDictionaryを使用できます
Mariusz Jamro

Dictionary拡張メソッドを使用した場合でも、常にオブジェクトを取得しますConcurrentDictionary。これは、バグの追跡が困難になる可能性があります。
マルセル

2

これは古い質問であることはわかっていますが、今はLINQがあるので、次のように1行で実行できます

Dictionary<T1,T2> merged;
Dictionary<T1,T2> mergee;
mergee.ToList().ForEach(kvp => merged.Add(kvp.Key, kvp.Value));

または

mergee.ToList().ForEach(kvp => merged.Append(kvp));

@Crucesの反対投票で申し訳ありませんが、最初の例は回答stackoverflow.com/a/6695211/704808を複製し、2番目の例は、から各項目を追加した後、拡張されたIEnumerable <KeyValuePair <string、string >>を破棄し続けますmergee

2

C#の新機能である複雑な答えを見るのが怖い。

ここにいくつかの簡単な答えがあります。
d1、d2などをマージして、辞書を作成し、重複するキーを処理します(以下の例では「b」)。

例1

{
    // 2 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };

    var result1 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=22, c=30    That is, took the "b" value of the last dictionary
}

例2

{
    // 3 dictionaries,  "b" key is common with different values

    var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
    var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };
    var d3 = new Dictionary<string, int>() { { "d", 40 }, { "b", 23 } };

    var result1 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
    // result1 is  a=10, b=21, c=30, d=40    That is, took the "b" value of the first dictionary

    var result2 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
    // result2 is  a=10, b=23, c=30, d=40    That is, took the "b" value of the last dictionary
}

より複雑なシナリオについては、他の回答を参照してください。
お役に立てば幸いです。


2
using System.Collections.Generic;
using System.Linq;

public static class DictionaryExtensions
{
    public enum MergeKind { SkipDuplicates, OverwriteDuplicates }
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, MergeKind kind = MergeKind.SkipDuplicates) =>
        source.ToList().ForEach(_ => { if (kind == MergeKind.OverwriteDuplicates || !target.ContainsKey(_.Key)) target[_.Key] = _.Value; });
}

あなたはスキップ/無視(デフォルト)または重複を上書きすることができます:そして、ボブはあなたの叔父さんです。ただし、Linqのパフォーマンスについて過度にうるさくなく、代わりに私がするように簡潔な保守可能なコードを好む場合:デフォルトのMergeKind.SkipDuplicatesを削除して強制することができます呼び出し元の選択、および開発者に結果がどうなるかを認識させる!


boolが実行するときに不必要なバイナリ列挙なしで以下の洗練された回答...
mattjs

2

「追加」と呼ばれる拡張メソッドを使用する場合は、コレクション初期化子を使用して、次のように必要な数の辞書を組み合わせることができます。

public static void Add<K, V>(this Dictionary<K, V> d, Dictionary<K, V> other) {
  foreach (var kvp in other)
  {
    if (!d.ContainsKey(kvp.Key))
    {
      d.Add(kvp.Key, kvp.Value);
    }
  }
}


var s0 = new Dictionary<string, string> {
  { "A", "X"}
};
var s1 = new Dictionary<string, string> {
  { "A", "X" },
  { "B", "Y" }
};
// Combine as many dictionaries and key pairs as needed
var a = new Dictionary<string, string> {
  s0, s1, s0, s1, s1, { "C", "Z" }
};

1

拡張メソッドを使用したマージ。重複するキーがある場合は例外をスローしませんが、それらのキーを2番目のディクショナリのキーで置き換えます。

internal static class DictionaryExtensions
{
    public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");

        var merged = new Dictionary<T1, T2>();
        first.ToList().ForEach(kv => merged[kv.Key] = kv.Value);
        second.ToList().ForEach(kv => merged[kv.Key] = kv.Value);

        return merged;
    }
}

使用法:

Dictionary<string, string> merged = first.Merge(second);

1

列挙型を使用するのではなく、存在する場合は非破壊マージのブールデフォルト、またはtrueの場合は完全に上書きするという以前の回答と比較して、使用を簡略化しました。それは、今までにない手の込んだコードを必要とすることなく、私自身のニーズにまだ適合しています:

using System.Collections.Generic;
using System.Linq;

public static partial class Extensions
{
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, bool overwrite = false)
    {
        source.ToList().ForEach(_ => {
            if ((!target.ContainsKey(_.Key)) || overwrite)
                target[_.Key] = _.Value;
        });
    }
}

0

EqualityComparer比較のためにアイテムを別の値/タイプにマップするを使用したマージ。ここではKeyValuePair(辞書を列挙するときの項目タイプ)からにマップしKeyます。

public class MappedEqualityComparer<T,U> : EqualityComparer<T>
{
    Func<T,U> _map;

    public MappedEqualityComparer(Func<T,U> map)
    {
        _map = map;
    }

    public override bool Equals(T x, T y)
    {
        return EqualityComparer<U>.Default.Equals(_map(x), _map(y));
    }

    public override int GetHashCode(T obj)
    {
        return _map(obj).GetHashCode();
    }
}

使用法:

// if dictA and dictB are of type Dictionary<int,string>
var dict = dictA.Concat(dictB)
                .Distinct(new MappedEqualityComparer<KeyValuePair<int,string>,int>(item => item.Key))
                .ToDictionary(item => item.Key, item=> item.Value);

0

または:

public static IDictionary<TKey, TValue> Merge<TKey, TValue>( IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
    {
        return x
            .Except(x.Join(y, z => z.Key, z => z.Key, (a, b) => a))
            .Concat(y)
            .ToDictionary(z => z.Key, z => z.Value);
    }

結果は、重複したエントリに対して「y」が勝つ結合になります。


0
public static IDictionary<K, V> AddRange<K, V>(this IDictionary<K, V> one, IDictionary<K, V> two)
        {
            foreach (var kvp in two)
            {
                if (one.ContainsKey(kvp.Key))
                    one[kvp.Key] = two[kvp.Key];
                else
                    one.Add(kvp.Key, kvp.Value);
            }
            return one;
        }

0

@ user166390からのバージョンはIEqualityComparer、大文字と小文字を区別しないキー比較を可能にするためにパラメーターが追加されています。

    public static T MergeLeft<T, K, V>(this T me, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        return me.MergeLeft(me.Comparer, others);
    }

    public static T MergeLeft<T, K, V>(this T me, IEqualityComparer<K> comparer, params Dictionary<K, V>[] others)
        where T : Dictionary<K, V>, new()
    {
        T newMap = Activator.CreateInstance(typeof(T), new object[] { comparer }) as T;

        foreach (Dictionary<K, V> src in 
            (new List<Dictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

0
fromDic.ToList().ForEach(x =>
        {
            if (toDic.ContainsKey(x.Key))
                toDic.Remove(x.Key);
            toDic.Add(x);
        });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.