2015-07-20 10 views
8

Voglio trovare una chiave in un dizionario e sostituire il valore se viene trovato o aggiungere la chiave/valore se non è .Crea dizionario con LINQ ed evita "elemento con la stessa chiave è già stato aggiunto" errore

Codice:

public class MyObject 
{ 

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

} 

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

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

soluzione foreach (opere):

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

} 

Mi è piaciuto molto la soluzione LINQ ma così com'è , genera l'errore sopra riportato. C'è un modo carino per evitare l'errore e usare LINQ?

+2

Usa 'ToLookup' invece di' ToDictionary' – EZI

+0

vorrei creare un 'MyObjectComparer' classe che implementa' 'IEqualityComparer e utilizzare la seguente riga:' Dictionary objectDict = csvEntries.Select (ingresso => entry.ToMyObject()). Distinct (new MyObjectComparer()). ToDictionary (csvEntry => csvEntry.UniqueKey, csvEntry => csvEntry); ' –

+0

L'indicizzatore aggiunge l'elemento se esiste, quindi è sufficiente rimuovere' ContainsKey 'controlla e usa sempre' objectDict [obj.UniqueKey] = obj'. – Lee

risposta

6

È possibile utilizzare GroupBy per creare chiavi univoche:

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

Tuttavia, invece di grp.First() si potrebbe creare una collezione con ToList o ToArray. In questo modo non prendi un oggetto arbitrario in caso di chiavi duplicate.

Un'altra opzione è utilizzare un Lookup<TKey, TValue> che consente chiavi duplicate e anche chiavi non esistenti, in questo caso si ottiene una sequenza vuota.

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

La prima soluzione ha funzionato per me, tuttavia 'ToDictionary (grp => grp.Key, grp => grp.First());' deve essere 'ToDictionary (grp => grp.Key, grp => grp.Last ()); 'perché voglio che il valore della chiave sia * sostituito * da una voce successiva. – TomSelleck

Problemi correlati