Diversi modi di aggiungere al dizionario


107

Qual è la differenza in Dictionary.add(key, value)e Dictionary[key] = value?

Ho notato che l'ultima versione non genera un ArgumentExceptionquando si inserisce una chiave duplicata, ma c'è qualche motivo per preferire la prima versione?

Modifica : qualcuno ha una fonte autorevole di informazioni su questo? Ho provato MSDN, ma è come sempre una caccia all'oca selvaggia :(

Risposte:


109

Le prestazioni sono quasi identiche al 100%. Puoi verificarlo aprendo la classe in Reflector.net

Questo è l'indicizzatore This:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

E questo è il metodo Add:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

Non pubblicherò l'intero metodo Insert poiché è piuttosto lungo, tuttavia la dichiarazione del metodo è questa:

private void Insert(TKey key, TValue value, bool add)

E più in basso nella funzione, succede questo:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

Che controlla se la chiave esiste già, e se lo fa e il parametro add è vero, genera l'eccezione.

Quindi, a tutti gli effetti, la performance è la stessa.

Come poche altre menzioni, si tratta solo di verificare se è necessario il controllo, per i tentativi di aggiungere la stessa chiave due volte.

Scusa per il lungo post, spero che vada bene.


+1 Molto interessante, grazie per il tuo post! Sembrerebbe che le prestazioni qui siano quasi identiche, come hanno accennato gli altri poster, comunque un'ottima scoperta :)
Sune Rievers

70

La prima versione aggiungerà una nuova KeyValuePair al dizionario, lanciando se la chiave è già nel dizionario. Il secondo, utilizzando l'indicizzatore, aggiungerà una nuova coppia se la chiave non esiste, ma sovrascriverà il valore della chiave se esiste già nel dizionario.

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

+1 Hai una fonte per le informazioni di cui sopra? Mi interessa sapere se ci sono effetti collaterali o avvertimenti nell'utilizzo del primo o dell'ultimo modulo.
Sune Rievers

3
Non ho davvero una fonte in quanto tale, appena fuori dalla mia testa, ma non penso che ci sia molto di più, di quanto menzionato negli altri commenti. Se ricordo bene, Aggiungi usa semplicemente l'indicizzatore, ma controlla prima se la chiave è già in uso.
hhravn

1
Risposta accettata modificata a quella di Steffen, perché la sua documentazione è di prim'ordine. Questa è comunque un'ottima risposta.
Sune Rievers

@Sune: Brutta mossa ... personalmente penso che questa risposta sia davanti a quella di Steffen ... dritto al punto e un buon esempio.
demoncodemonkey

1
@SuneRievers Penso che sarà più utile per le persone, se accettata, risposta per questo, invece della risposta attualmente accettata. Perché questo risponde esattamente alla domanda ("qual è la differenza"), piuttosto che a quella accettata (che parla di prestazioni, e quasi il 99% degli utenti che cercano questo argomento (come me), aveva bisogno della "differenza" (perché l'ho incontrato argomento), e la risposta accettata era inutile per me e spreca il nostro secondo. invece, questa risposta è esatta.
T.Todua,

30

Dictionary.Add(key, value)e Dictionary[key] = valuehanno scopi diversi:

  • Utilizza il Addmetodo per aggiungere una nuova coppia chiave / valore, le chiavi esistenti non verranno sostituite ( ArgumentExceptionviene generato un messaggio).
  • Usa l'indicizzatore se non ti interessa se la chiave esiste già nel dizionario, in altre parole: aggiungi la coppia chiave / valore se la chiave non è nel dizionario o sostituisci il valore per la chiave specificata se la chiave è già nel dizionario.

1
Il codice che auto-descrive l'intento è importante e immensamente prezioso (e richiede pochi o nessun commento). Questa risposta mostra la differenza di intenti con entrambi i metodi e dovrebbe essere seguita quando si sceglie uno. In altre parole, non utilizzare "indexer add" quando sai in anticipo che aggiungerai sempre, o addirittura dovrai sempre aggiungere. Avere un'eccezione IndexOutOfBounds generata è meglio di un comportamento imprevisto.
ryancdotnet

28

Per rispondere alla domanda prima dobbiamo dare un'occhiata allo scopo di un dizionario e alla tecnologia sottostante.

Dictionaryè l'elenco di KeyValuePair<Tkey, Tvalue>dove ogni valore è rappresentato dalla sua chiave univoca. Diciamo che abbiamo un elenco dei tuoi cibi preferiti. Ogni valore (nome del cibo) è rappresentato dalla sua chiave univoca (una posizione = quanto ti piace questo cibo).

Codice di esempio:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

Diciamo che vuoi restare in salute, hai cambiato idea e vuoi sostituire il tuo "Burger" preferito con l'insalata. Il tuo elenco è ancora un elenco dei tuoi preferiti, non cambierai la natura dell'elenco. Il tuo preferito rimarrà il numero uno della lista, solo il suo valore cambierà. Questo è quando lo chiami:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

Ma non dimenticare che sei il programmatore e da ora in poi finisci le tue frasi con; ti rifiuti di usare gli emoji perché genererebbero un errore di compilazione e tutto l'elenco dei preferiti è basato su 0 indice.

Anche la tua dieta è cambiata! Quindi modifichi di nuovo la tua lista:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

Ci sono due possibilità con la definizione, o vuoi dare una nuova definizione per qualcosa che non esisteva prima o vuoi cambiare la definizione che già esiste.

Il metodo Aggiungi ti consente di aggiungere un record ma solo a una condizione: la chiave per questa definizione potrebbe non esistere nel dizionario.

Ora guarderemo sotto il cofano. Quando si crea un dizionario, il compilatore effettua una prenotazione per il bucket (spazi in memoria per archiviare i record). Bucket non memorizza le chiavi nel modo in cui le definisci. Ogni chiave viene sottoposta ad hashing prima di passare al bucket (definito da Microsoft), vale la pena ricordare che la parte del valore rimane invariata.

Userò l'algoritmo di hashing CRC32 per semplificare il mio esempio. Quando definisci:

myDietFavorites[0] = "Pizza";

Quello che sta per finire nel secchio è db2dc565 "Pizza" (semplificato).

Quando modifichi il valore con:

myDietFavorites[0] = "Spaghetti";

Hai cancellato il tuo 0 che è di nuovo db2dc565, quindi cerchi questo valore nel tuo bucket per trovare se è lì. Se è lì, riscrivi semplicemente il valore assegnato alla chiave. Se non è lì, metterai il tuo valore nel secchio.

Quando chiami la funzione Aggiungi sul tuo dizionario come:

myDietFavorite.Add(0, "Chocolate");

Hai cancellato il tuo 0 per confrontare il suo valore con quelli nel secchio. Puoi metterlo nel secchio solo se non è lì .

È fondamentale sapere come funziona, soprattutto se lavori con dizionari di stringhe o caratteri di chiave. Fa distinzione tra maiuscole e minuscole a causa dell'hashing. Quindi per esempio "nome"! = "Nome". Usiamo il nostro CRC32 per descrivere questo.

Il valore per "nome" è: e04112b1 Il valore per "Nome" è: 1107fb5b


Queste due righe sono sufficienti per capire ....... Ci sono due possibilità con la definizione, o vuoi dare una nuova definizione per qualcosa che non esisteva prima o vuoi cambiare la definizione che già esiste. Il metodo Aggiungi ti consente di aggiungere un record ma solo a una condizione: la chiave per questa definizione potrebbe non esistere nel dizionario.
Niraj Trivedi

4

Sì, questa è la differenza, il metodo Add genera un'eccezione se la chiave esiste già.

Il motivo per utilizzare il metodo Add è esattamente questo. Se il dizionario non dovrebbe contenere già la chiave, di solito si desidera l'eccezione in modo da essere consapevoli del problema.


0

Date le somiglianze più che probabili nelle prestazioni, usa ciò che ritieni più corretto e leggibile per il pezzo di codice che stai utilizzando.

Sento un'operazione che descrive un'aggiunta, essendo la presenza della chiave già un'eccezione davvero rara è meglio rappresentata con l'add. Semanticamente ha più senso.

La dict[key] = valuerappresenta meglio una sostituzione. Se vedo quel codice mi aspetto che la chiave sia già comunque nel dizionario.


Presumo che ci sia un piccolo guadagno in termini di prestazioni dal non controllare se la chiave esiste prima. Non mi sarei aspettato dic[key] = valueche la chiave fosse già presente, ma immagino sia discutibile;)
Sune Rievers

2
+ Penso che il lancio non dovrebbe mai essere usato per controllare se la chiave è già rappresentata. if (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn

0

Uno sta assegnando un valore mentre l'altro sta aggiungendo al dizionario una nuova chiave e valore.


0

Per inserire il valore nel dizionario

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.