2015-07-20 32 views
8

Ich möchte einen Schlüssel in einem Wörterbuch und den Wert ersetzen, wenn es gefunden wird oder den Schlüssel/Wert hinzufügen, wenn es nicht ist .Erstellen Sie Wörterbuch mit LINQ und vermeiden Sie "Element mit dem gleichen Schlüssel wurde bereits hinzugefügt" Fehler

Code:

public class MyObject 
{ 

    public string UniqueKey { get; set; } 
    public string Field1 { get; set; } 
    public string Field2 { get; set; } 

} 

LINQ Solution (wirft An item with the same key has already been added.):

Dictionary<string, MyObject> objectDict = csvEntries.ToDictionary(csvEntry => csvEntry.ToMyObject().UniqueKey, csvEntry => csvEntry.ToMyObject()); 

FürJeden Lösung (Werke):

Dictionary<string, MyObject> objectDict = new Dictionary<string, MyObject>(); 
foreach (CSVEntry csvEntry in csvEntries) 
{ 

    MyObject obj = csvEntry.ToMyObject(); 

    if (objectDict.ContainsKey(obj.UniqueKey)) 
    { 
     objectDict[obj.UniqueKey] = obj; 
    } 
    else { 
     objectDict.Add(obj.UniqueKey, obj); 
    } 

} 

ich wirklich die LINQ-Lösung mochte aber, wie es steht , es löst den obigen Fehler aus. Gibt es eine nette Möglichkeit, den Fehler zu vermeiden und LINQ zu verwenden?

+2

Verwenden 'ToLookup' statt' ToDictionary' – EZI

+0

Ich würde eine Klasse 'MyObjectComparer' erstellen, die' IEqualityComparer 'implementiert und verwenden Sie die folgende Zeile ein:' Dictionary objectDict = csvEntries.Select (Eintrag => entry.ToMyObject()). Distinct (neu MyObjectComparer()). ToDictionary (csvEntry => csvEntry.UniqueKey, csvEntry => csvEntry); ' –

+0

Der Indexer fügt das Element hinzu, wenn es existiert, so dass Sie den' ContainsKey einfach entfernen können 'check und benutze immer' objectDict [obj.UniqueKey] = obj'. – Lee

Antwort

6

können Sie GroupBy verwenden, um eindeutige Schlüssel zu erstellen:

Dictionary<string, MyObject> objectDict = csvEntries 
    .Select(csvEntry => csvEntry.ToMyObject()) 
    .GroupBy(x => x.UniqueKey) 
    .ToDictionary(grp => grp.Key, grp => grp.First()); 

Doch statt grp.First() Sie eine Sammlung mit ToList oder ToArray schaffen könnte. Auf diese Weise nehmen Sie kein beliebiges Objekt im Falle von doppelten Schlüsseln.

Eine weitere Option ist die Verwendung einer Lookup<TKey, TValue>, die doppelte Schlüssel und sogar nicht vorhandene Schlüssel erlaubt. In diesem Fall erhalten Sie eine leere Sequenz.

var uniqueKeyLookup = csvEntries 
    .Select(csvEntry => csvEntry.ToMyObject()) 
    .ToLookup(x => x.UniqueKey); 
IEnumerable<MyObject> objectsFor1234 = uniqueKeyLookup["1234"]; // empty if it doesn't exist 
+0

Die erste Lösung funktionierte für mich, 'ToDictionary (grp => grp.Key, grp => grp.First());' muss 'ToDictionary (grp => grp.Key, grp => grp.Last ()); 'weil ich möchte, dass der Wert des Schlüssels * durch einen späteren Eintrag ersetzt wird. – TomSelleck

Verwandte Themen