2012-04-04 5 views
1

Ich versuche, zwei Wörterbücher zu vergleichen, die geladen werden. Jede Person enthält eine ID und ein Individual-Objekt.Vergleichen zweier Wörterbücher und Hinzufügen eines Wörterbuchwerts zu einem anderen Wörterbuch C#

Der Code so weit ist

  _Individuals1 = file1.fileIndividuals; 
     _Individuals2 = file2.fileIndividuals; 

     foreach (KeyValuePair<int, Individual> kvpInd in _Individuals1) 
     { 
      foreach (KeyValuePair<int, Individual> kvpInd2 in _Individuals2) 
      { 
       if (kvpInd.Value.name.name == kvpInd2.Value.name.name) 
       { 
        similarInds.Add(kvpInd.Key, kvpInd.Value); 
       } 
      } 
     } 

und im den Fehler des Erhaltens „ein Element mit demselben Schlüssel hinzugefügt wurde bereits.“ Ich kann irgendwie sehen, warum, aber ich bin nicht sicher, wie es anders geht, damit es funktioniert. Kann mir bitte jemand helfen?

Danke

+1

Was ist _supposed_, wenn 'name.name' mehrere Treffer hat? –

Antwort

1

Sie können mehrere Einträge mit demselben Wert in einem Wörterbuch haben. Sie tun nichts, um die Schlüssel zu überprüfen oder zu vergleichen.

So haben Sie mehrere Einträge in _Individuals2 mit dem gleichen Wert, obwohl sie verschiedene Schlüssel haben.

Ich weiß nicht, was Sie hier tun, aber ich würde denken, dass Ihre Schlüssel sein sollten, was jedes Objekt einzigartig macht, und sie sollten wirklich nicht die Werte vergleichen. Wenn Sie eine Liste oder etwas Ähnliches verwenden, können Sie einfach die Intersection-Methode verwenden, um die Gemeinsamkeiten zurückzugeben.

Oder Sie könnten nur verwenden

_Individuals1.Values.Intersect(_Individuals2.Values); 

Auch wenn mit Generika herum spielen, ist es fast immer auszahlt die Gleichstellung Betreiber der Objekte außer Kraft zu setzen in der generischen gespeichert werden.Dann müssen Sie nicht tun müssen, um Dinge wie:

if (kvpInd.Value.name.name == kvpInd2.Value.name.name) 
+0

scheint es, dass die Schnittpunktmethode am besten funktioniert :) Danke! – user1290653

1

Das Problem hierbei ist, dass Sie eine schlechte Annahme über die Beziehung zwischen Schlüsseln und Werten in verschiedenen Dictionary<TKey, TValue> Instanzen haben. Es ist sehr gut möglich, dass mehrere Einträge unterschiedliche Schlüssel, aber denselben Wert haben. Wenn das in _Individuals2 passiert, dann werden Sie den gleichen Schlüssel zweimal zum Wörterbuch hinzufügen. Betrachten

Map1

  • Key 1, Wert Dog

Map2

  • Key 2, Wert Dog
  • Taste 3, Wert Dog

In In diesem Szenario haben mehrere Werte in Map2 den Wert Hund. Also würde ich bis im Wesentlichen am Ende der folgenden Ausführung basiert auf dem Algorithmus

// 1:Dog matches 2:Dog 
similarInds.Add(1, "Dog"); 
// 1:Dog matches 3:Dog 
similarInds.Add(1, "Dog"); 

Es scheint, wie das, was Sie hier wollen, ist einfach zu kennen den Satz von Individual Objekte, die zwischen den beiden Karten ähnlich sind. Wenn ja, dann speichern Sie einfach den Wert und verwenden Sie eine Set<Individual>, um Dubletten zu vermeiden.

var similarInds = new HashSet<Individual>(); 
... 

similarInds.Add(kvpInd.Value); 
+0

mag es nicht, wenn ich versuche, var aslyInds = new Set (); anscheinend Set existiert nicht – user1290653

+0

@ user1290653 Entschuldigung, sollte 'HashSet ' gewesen sein. Aktualisiert meine Antwort – JaredPar

+0

Wie erstelle ich das dann in eine Datenquelle für eine Listbox (lstIndividuals.DataSource) – user1290653

1

Hier ist, wie Sie es mit lambda tun:

var similarInds = file1.fileIndividuals. 
Where(kv1 => file2.fileIndividuals.Any(kv2 => kv1.Value.name.name == kv2.Value.name.name)). 
ToDictionary(kv => kv.Key, kv => kv.Value); 
0

Lassen Sie sich einen Schritt hierher zurück. Sie haben zwei Wörterbücher, die Einzelpersonen mit einer Ganzzahl verknüpfen. Sie vergleichen jedoch nicht die Schlüssel der relativen Wörterbücher, sondern deren Werte. Das lässt mich denken, dass die Schlüssel nicht einzigartig sind.

Es klingt wie das, was Sie wollen, dass die vollständige äußere ist beiden Wörterbücher kommen von:

  • In Fällen, in denen eine Person in nur File1 vorhanden ist, verwenden Sie den Schlüssel und Wert für die Person von File1.
  • Dito für Einzelpersonen nur in File2.
  • Fügen Sie die Datensätze zusammen, wenn beide Dateien die gleiche Person (nach Name) enthalten.

Dies kann mit einigen Linq erreicht werden. Verstehe, dass dies nicht die leistungsfähigste der möglichen Lösungen sein wird, aber es ist ein wenig einfacher zu verstehen, was vor sich geht.

//get records from 1 that aren't in 2 
var left = _Individuals1.Where(l=>!_Individuals2.Any(r=>l.Value.Name == r.Value.Name)); 
//get records that appear in both 1 and 2, 
//using the select clause to "merge" the data you want from each side 
var join = from l in _Individuals1 
      join r in _Individuals2 on l.Value.Name equals r.Value.Name 
      select new KeyValuePair<int, Individual>(l.Key, r.Value); 
//get records from 2 that aren't in 1 
var right = _Individuals2.Where(r=>!_Individuals1.Any(l=>l.Value.Name == r.Value.Name)); 

//Now, the keys from the left and join enumerables should be consistent, 
//because we used the keys from _Individuals1 in both of them. 
var merged = left.Concat(join).ToDictionary(x=>x.Key, x=>x.Value); 

//BUT, keys from records that only existed in 2 may have duplicate keys, 
//so don't trust them 
var maxKey = merged.Keys.Max(); 
foreach(var r in right) 
    merged.Add(++maxKey, r.Value); 

können Sie vermeiden, die „links“ zählbare explizit erstellen, indem Sie die Abfrage Strukturierung, die „join“ erzeugt eine links zu erzeugen verbinden anstelle der inneren Verknüpfung I zeigen. Sie können auch versuchen, Schlüssel von _Individuals2 zu verwenden, indem Sie sie jeweils für das zusammengeführte Verzeichnis überprüfen. Dieser Code würde wie folgt aussehen:

var maxKey = merged.Keys.Max(); 
foreach(var r in right) 
    if(merged.ContainsKey(r.Key)) 
     merged.Add(++maxKey, r.Value); 
    else 
    { 
     merged.Add(r.Key, r.Value); 
     maxKey = r.Key > maxKey ? r.Key : maxKey; 
    } 

Diese sicher Schlüssel von _Individuals2 verwenden, wenn der Schlüssel nicht ein Duplikat sei, so dass einige (aber wahrscheinlich nicht alle) Schlüssel von _Individuals2 verwendet werden sollen. Ob das "besser" ist, hängt von der genauen Situation ab.

+0

gibt es einen Fehler auf der Linie Join r in _Individuals2 auf l.Value.Name == r.Value.Name :( – user1290653

+0

ich glaube nicht, dass es den r.Value.name Teil – user1290653

+0

Edited gefallen, anstelle eines '==' -Operators Sie müssen das Schlüsselwort 'equals' verwenden. Die Angabe der Verbindungskriterien ist kein Ausdruck, sondern definiert die Projektionen der beiden Enumerables, die im Vergleich gleich sein müssen. Wenn Sie die Methode Enumerable.Join betrachten, die dahinter verwendet wird die Szenen, die klarer sind, es wird erwartet, dass Sie zwei Lambdas bereitstellen, die den "inneren Schlüssel" und den "äußeren Schlüssel" zurückgeben. – KeithS

Verwandte Themen