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)

409voto

Jon Skeet Punkte 1325502

Dies hängt zum Teil davon ab, was passieren soll, wenn Sie auf Duplikate stoßen. Sie könnten zum Beispiel Folgendes tun:

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

Dies führt zu einer Ausnahme, wenn Sie doppelte Schlüssel erhalten.

EDIT: Wenn Sie ToLookup verwenden, erhalten Sie ein Lookup, das mehrere Werte pro Schlüssel haben kann. Sie könnte dann in ein Wörterbuch umwandeln:

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

Es ist ein bisschen hässlich - und ineffizient - aber es ist der schnellste Weg, um es in Bezug auf den Code zu tun. (Ich habe es nicht getestet, zugegeben.)

Sie könnten Ihre eigene ToDictionary2-Erweiterungsmethode natürlich schreiben (mit einem besseren Namen, aber ich habe keine Zeit, mir jetzt einen auszudenken) - es ist nicht furchtbar schwer zu tun, nur überschreiben (oder ignorieren) doppelte Schlüssel. Der wichtige Teil ist (meiner Meinung nach) die Verwendung von SelectMany und die Erkenntnis, dass ein Wörterbuch die Iteration über seine Schlüssel/Wertpaare unterstützt.

361voto

Jonas Stensved Punkte 12881

Ich würde es folgendermaßen machen:

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

Einfach und leicht. Laut dieser Blogbeitrag sie ist sogar schneller als die meisten Schleifen, da die ihr zugrunde liegende Implementierung auf Elemente über einen Index und nicht über einen Enumerator zugreift (siehe diese Antwort) .

Es wird natürlich eine Ausnahme geworfen, wenn es Duplikate gibt, so dass Sie vor dem Zusammenführen prüfen müssen.

120voto

Dies führt nicht zu einer Explosion, wenn es mehrere Schlüssel gibt ("rechte" Schlüssel ersetzen "linke" Schlüssel), kann eine Reihe von Wörterbüchern zusammenführen (falls gewünscht) und bewahrt den Typ (mit der Einschränkung, dass es einen sinnvollen öffentlichen Standardkonstruktor erfordert):

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

}

64voto

orip Punkte 69138

Die triviale Lösung wäre:

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

30voto

JaredPar Punkte 699699

Versuchen Sie Folgendes

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

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