Was ist der beste Weg, um zwei oder mehr Wörterbücher zusammenzuführen (Dictionary<T1,T2>
) in C # zusammenzuführen? (3.0 Funktionen wie LINQ sind in Ordnung).
Ich denke an eine Methodensignatur im Sinne von:
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);
oder
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 bekommen, aber ich habe an etwas gedacht, das doppelte Schlüssel handhabt. Im Falle einer Kollision spielt es keine Rolle, welcher Wert im Diktat gespeichert wird, solange er konsistent ist.
c#
dictionary
merge
orip
quelle
quelle
dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)
dictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)
.Antworten:
Dies hängt teilweise davon ab, was passieren soll, wenn Sie auf Duplikate stoßen. Zum Beispiel könnten Sie tun:
Dies löst eine Ausnahme aus, wenn Sie doppelte Schlüssel erhalten.
BEARBEITEN: Wenn Sie ToLookup verwenden, erhalten Sie eine Suche, die mehrere Werte pro Schlüssel haben kann. Sie könnten das dann in ein Wörterbuch konvertieren:
Es ist ein bisschen hässlich - und ineffizient - aber es ist der schnellste Weg, es in Bezug auf Code zu tun. (Ich habe es zugegebenermaßen nicht getestet.)
Sie könnten natürlich Ihre eigene ToDictionary2-Erweiterungsmethode schreiben (mit einem besseren Namen, aber ich habe jetzt keine Zeit, mir eine auszudenken) - es ist nicht besonders schwer, doppelte Schlüssel zu überschreiben (oder zu ignorieren). Das Wichtigste (meiner Meinung nach) ist die Verwendung von SelectMany und die Erkenntnis, dass ein Wörterbuch die Iteration über seine Schlüssel / Wert-Paare unterstützt.
quelle
GroupBy
könnte zwar etwas effizienter sein - aber ich bezweifle, dass dies in beiden Fällen von Bedeutung ist.ToDictionary
Methodenaufruf bereitgestellt wird . Ich würde es jedoch vorziehen, die Antwort für den häufigeren Fall einfacher zu halten, und ich hoffe, dass jeder, der einen benutzerdefinierten Vergleicher benötigt, in der Lage ist, die relevante Überlastung zu finden.Ich würde es so machen:
Simpel und einfach. Laut diesem Blog-Beitrag ist es sogar schneller als die meisten Schleifen, da die zugrunde liegende Implementierung eher über den Index als über den Enumerator auf Elemente zugreift (siehe diese Antwort) .
Es wird natürlich eine Ausnahme auslösen, wenn es Duplikate gibt, daher müssen Sie dies vor dem Zusammenführen überprüfen.
quelle
dictionaryFrom.ToList().ForEach(x => dictionaryTo[x.Key] = x.Value)
. Auf diese WeisedictionaryFrom
überschreiben die Werte von den Wert für einen möglicherweise vorhandenen Schlüssel.Dies explodiert nicht, wenn mehrere Schlüssel vorhanden sind ("rechte" Schlüssel ersetzen "lefter" Schlüssel), kann eine Reihe von Wörterbüchern zusammenführen (falls gewünscht) und behält den Typ bei (mit der Einschränkung, dass ein aussagekräftiger öffentlicher Standardkonstruktor erforderlich ist):
quelle
this T me
Wörterbuch mitnew Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase)
oder ähnlich deklariert wurde, behält das resultierende Wörterbuch nicht das gleiche Verhalten bei.me
einDictionary<K,V>
, können Sie tunvar newMap = new Dictionary<TKey, TValue>(me, me.Comparer);
, und Sie haben auch den zusätzlichen vermeidenT
Typparameter.Die triviale Lösung wäre:
quelle
Versuche Folgendes
quelle
quelle
foreach(var kvp in Message.GetAttachments().Union(mMessage.GetImages()))
Wenn es Nachteile im Produktionscode gibt, lassen Sie es mich bitte wissen! :)IEnumerable<KeyValuePair<TKey, TValue>>
bei der Gleichheit durch Gleichheit von Schlüssel und Wert definiert wird (es gibt eine Überlastung, um Alternativen zuzulassen). Dies ist in Ordnung für eine foreach-Schleife, in der dies alles ist, was erforderlich ist, aber es gibt Fälle, in denen Sie das Wörterbuch tatsächlich möchten.Ich bin sehr spät zur Party und vermisse vielleicht etwas, aber wenn entweder keine doppelten Schlüssel vorhanden sind oder, wie das OP sagt: "Im Falle einer Kollision spielt es keine Rolle, welcher Wert für das Diktat gespeichert wird, solange es ist konsistent: "Was ist los mit diesem (Zusammenführen von D2 zu D1)?
Es scheint einfach genug, vielleicht zu einfach, ich frage mich, ob mir etwas fehlt. Dies ist, was ich in einem Code verwende, in dem ich weiß, dass es keine doppelten Schlüssel gibt. Ich bin jedoch noch im Testen, daher würde ich jetzt gerne wissen, ob ich etwas übersehen habe, anstatt es später herauszufinden.
quelle
Folgendes funktioniert für mich. Wenn es Duplikate gibt, wird der Wert von dictA verwendet.
quelle
Hier ist eine Hilfsfunktion, die ich benutze:
quelle
if(first == null)
dann ist diese Logik nutzlos , dafirst
ist nichtref
und wird nicht zurückgegeben. Und es kann nicht sein,ref
dass es als Schnittstelleninstanz deklariert ist. Sie müssen entweder die Fehlerprüfung entfernen oder als Klasseninstanz deklarieren oder einfach ein neues Wörterbuch zurückgeben (ohne Erweiterungsmethode).Option 1: Dies hängt davon ab, was passieren soll, wenn Sie sicher sind, dass Sie in beiden Wörterbüchern keinen doppelten Schlüssel haben. als du tun könntest:
Hinweis : Dies führt zu Fehlern, wenn Sie doppelte Schlüssel in Wörterbüchern erhalten.
Option 2: Wenn Sie einen doppelten Schlüssel haben können, müssen Sie den doppelten Schlüssel mit der where-Klausel behandeln.
Hinweis: Es wird kein doppelter Schlüssel erhalten. Wenn es einen doppelten Schlüssel gibt, erhält er den Schlüssel von dictionary1.
Option 3: Wenn Sie ToLookup verwenden möchten. Dann erhalten Sie eine Suche, die mehrere Werte pro Schlüssel haben kann. Sie können diese Suche in ein Wörterbuch konvertieren:
quelle
Wie wäre es mit einer
params
Überladung?Außerdem sollten Sie sie
IDictionary
für maximale Flexibilität eingeben.quelle
In Anbetracht der Leistung beim Suchen und Löschen von Wörterbuchschlüsseln, da es sich um Hash-Operationen handelt, und angesichts des Wortlauts der Frage, der der beste Weg war, denke ich, dass das Folgende ein vollkommen gültiger Ansatz ist und die anderen meiner Meinung nach etwas zu kompliziert sind.
ODER wenn Sie in einer Multithread-Anwendung arbeiten und Ihr Wörterbuch ohnehin threadsicher sein muss, sollten Sie Folgendes tun:
Sie können dies dann umbrechen, um eine Aufzählung von Wörterbüchern zu verarbeiten. Unabhängig davon sehen Sie ungefähr ~ O (3n) (alle Bedingungen sind perfekt), da die
.Add()
einen zusätzlichen, unnötigen, aber praktisch kostenlosen,Contains()
hinter die Kulissen werfen. Ich denke nicht, dass es viel besser wird.Wenn Sie zusätzliche Vorgänge für große Sammlungen einschränken möchten, sollten
Count
Sie die Größe jedes Wörterbuchs, das Sie zusammenführen möchten, zusammenfassen und die Kapazität des Zielwörterbuchs auf diese festlegen, wodurch die späteren Kosten für die Größenänderung vermieden werden. Das Endprodukt ist also ungefähr so ...Beachten Sie, dass ich mich
IList<T>
für diese Methode entschieden habe ... hauptsächlich, weil Sie sich bei der Aufnahme einer MethodeIEnumerable<T>
für mehrere Aufzählungen desselben Satzes geöffnet haben. Dies kann sehr kostspielig sein, wenn Sie Ihre Sammlung von Wörterbüchern von einem zurückgestellten LINQ erhalten haben Aussage.quelle
Basierend auf den obigen Antworten, aber Hinzufügen eines Func-Parameters, damit der Aufrufer die Duplikate verarbeiten kann:
quelle
Die Party ist jetzt ziemlich tot, aber hier ist eine "verbesserte" Version von user166390, die ihren Weg in meine Erweiterungsbibliothek gefunden hat. Abgesehen von einigen Details habe ich einen Delegaten hinzugefügt, um den zusammengeführten Wert zu berechnen.
quelle
@Tim: Sollte ein Kommentar sein, aber Kommentare erlauben keine Code-Bearbeitung.
Hinweis: Ich habe die Änderung von @ANeves auf die Lösung von @Andrew Orsich angewendet, sodass MergeLeft jetzt folgendermaßen aussieht:
quelle
Dictionary
Typen. Überladungen könnten für andere Wörterbuchtypen (ConcurrentDictionary
,ReadOnlyDictionary
usw.) hinzugefügt werden. Ich denke nicht, dass die Erstellung einer neuen Liste und concat persönlich erforderlich ist. Ich habe gerade zuerst das params-Array iteriert und dann jede KVP jedes Wörterbuchs iteriert. Ich sehe keinen Nachteil.Dictionary
Objekt erhalten, selbst wenn Sie die Erweiterungsmethode für a verwenden würdenConcurrentDictionary
. Das könnte zu schwer auffindbaren Fehlern führen.Ich weiß, dass dies eine alte Frage ist, aber da wir jetzt LINQ haben, können Sie dies in einer einzigen Zeile wie dieser tun
oder
quelle
mergee
.Ich hatte Angst, komplexe Antworten zu sehen, weil ich neu in C # war.
Hier sind einige einfache Antworten.
Zusammenführen von d1, d2 usw. Wörterbüchern und Behandeln überlappender Schlüssel ("b" in den folgenden Beispielen):
Beispiel 1
Beispiel 2
Für komplexere Szenarien siehe andere Antworten.
Hoffe das hat geholfen.
quelle
Sie können die Duplikate entweder überspringen / ignorieren (Standard) oder überschreiben: Und Bob ist Ihr Onkel, vorausgesetzt, Sie sind nicht übermäßig pingelig in Bezug auf die Linq-Leistung, sondern bevorzugen einen präzisen, wartbaren Code wie ich: In diesem Fall können Sie die Standard-MergeKind.SkipDuplicates entfernen, um sie zu erzwingen eine Wahl für den Anrufer und machen Sie den Entwickler auf die Ergebnisse aufmerksam!
quelle
Beachten Sie, dass Sie bei Verwendung einer Erweiterungsmethode namens "Hinzufügen" Sammlungsinitialisierer verwenden können, um so viele Wörterbücher wie nötig wie folgt zu kombinieren:
quelle
Zusammenführen mit einer Erweiterungsmethode. Es wird keine Ausnahme ausgelöst, wenn doppelte Schlüssel vorhanden sind, sondern diese Schlüssel werden durch Schlüssel aus dem zweiten Wörterbuch ersetzt.
Verwendungszweck:
quelle
Vereinfacht von der Verwendung im Vergleich zu meiner früheren Antwort mit einem Bool-Standardwert für zerstörungsfreie Zusammenführung, wenn vorhanden, oder vollständig überschreiben, wenn wahr, anstatt eine Aufzählung zu verwenden. Es entspricht immer noch meinen eigenen Bedürfnissen, ohne dass jemals ein schickerer Code benötigt wird:
quelle
Zusammenführen mit einem
EqualityComparer
, der Elemente zum Vergleich mit einem anderen Wert / Typ abbildet. Hier werden wir vonKeyValuePair
(Elementtyp beim Aufzählen eines Wörterbuchs) auf zuordnenKey
.Verwendungszweck:
quelle
oder :
Das Ergebnis ist eine Vereinigung, bei der bei doppelten Einträgen "y" gewinnt.
quelle
quelle
Eine Version von @ user166390 antwortet mit einem zusätzlichen
IEqualityComparer
Parameter, um einen Schlüsselvergleich ohne Berücksichtigung der Groß- und Kleinschreibung zu ermöglichen.quelle
quelle