639 Stimmen

Zusammenführen von Wörterbüchern in C#

Wie lassen sich 2 oder mehr Wörterbücher am besten zusammenführen ( Dictionary<T1,T2> ) in C#? (3.0-Funktionen wie LINQ sind in Ordnung).

Ich denke an eine Methodensignatur in der Art von:

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

o

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

EDIT: Ich habe eine coole Lösung von JaredPar und Jon Skeet, aber ich dachte an etwas, das mit doppelten Schlüsseln umgehen kann. Im Falle einer Kollision spielt es keine Rolle, welcher Wert im Diktat gespeichert wird, solange er konsistent ist.

238 Stimmen

Unabhängig davon, aber für jeden, der nur zwei Wörterbücher ohne Prüfung auf doppelte Schlüssel zusammenführen möchte, funktioniert dies sehr gut: dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)

8 Stimmen

@Benjol Sie hätten dies im Antwortabschnitt hinzufügen können

8 Stimmen

Clojure's Zusammenführung in C#: dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)

3voto

Andy Punkte 3420

Wenn Sie eine Erweiterungsmethode namens "Add" verwenden, können Sie Auflistungsinitialisierungen verwenden, um so viele Wörterbücher wie nötig zu kombinieren:

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" }
};

2voto

mattjs Punkte 111
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; });
}

Sie können die Duplikate entweder überspringen/ignorieren (Standard) oder überschreiben: In diesem Fall können Sie die Standardeinstellung MergeKind.SkipDuplicates entfernen, um dem Aufrufer eine Wahlmöglichkeit einzuräumen und dem Entwickler bewusst zu machen, was die Ergebnisse sein werden!

1voto

keni Punkte 1642

@Tim: Es sollte ein Kommentar sein, aber Kommentare erlauben keine Bearbeitung des Codes.

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

Hinweis: Ich habe die Änderung von @ANeves auf die Lösung von @Andrew Orsich angewendet, so dass die MergeLeft jetzt so aussieht:

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

1voto

Cruces Punkte 2683

Ich weiß, dies ist eine alte Frage, aber da wir jetzt LINQ haben, können Sie es in einer einzigen Zeile wie folgt tun

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

ou

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

1voto

Ich habe Angst, komplexe Antworten zu sehen, da ich neu in C# bin.

Hier sind einige einfache Antworten.
Zusammenführung der Wörterbücher d1, d2 usw. und Behandlung sich überschneidender Schlüssel ("b" in den folgenden Beispielen):

Beispiel 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
}

Beispiel 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
}

Für komplexere Szenarien siehe andere Antworten.
Ich hoffe, das hat geholfen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X