Dizionario vs Elenco


30

Così ho incontrato un Dictionary<int, int>oggi al lavoro. Questo mi è sembrato strano perché probabilmente avrei usato solo un List<int>invece. C'è una differenza e ci sarebbe un caso d'uso in cui una struttura sarebbe preferita rispetto all'altra?


1
Deve esserci una relazione tra due (o più) dati forniti? Quindi la mappa (dizionario in questa lingua) ha un senso.
Rig

3
Il dizionario dei nomi mi rende ovvio. Quando hai bisogno di cercare qualcosa velocemente, usi un dizionario.
ChaosPandion

2
@ChaosPandion: a List<T>all'interno del framework .NET è un array ad accesso casuale, in cui un'operazione di ricerca è in genere più veloce rispetto a a Dictionary<int,T>.
Doc Brown

2
@DocBrown - Solo nel caso piuttosto strano dell'uso dell'indice numerico come chiave. Un altro aspetto saggio sarà più veloce durante l'utilizzo Dictionary<TKey, TValue>.
ChaosPandion

2
@chaos questa domanda riguarda questo strano caso.
MarkJ

Risposte:


32

Utilizzeresti un Dictionary<int, int>se i tuoi indici hanno un significato speciale oltre al posizionamento posizionale.

L'esempio immediato che viene in mente è la memorizzazione di una colonna ID e una colonna int in un database. Ad esempio, se si dispone di una [person-id]colonna e una [personal-pin]colonna, è possibile inserirle in a Dictionary<int, int>. In questo modo pinDict[person-id]ti dà un PIN, ma l'indice è significativo e non solo una posizione in a List<int>.

Ma davvero, ogni volta che hai due elenchi correlati di numeri interi, questa potrebbe essere una struttura di dati appropriata.


Se il mio id-persona proviene da un intervallo 0, ..., 999 e dovrei caricare i valori dei pin personali in memoria per tutte le 1000 persone, sceglierei tipicamente un List<int>e non un dizionario. Vedi la mia risposta qui sotto.
Doc Brown

3
si ma un dizionario può essere sparse
jk.

@jk: questo è esattamente ciò che ho cercato di elaborare nella mia risposta.
Doc Brown

7
Pin personale? Sembra un po 'ridondante.
Jack,

Hm, quando l'indice ha "un significato speciale", negli scenari del mondo reale può essere probabile che non formino un intervallo contiguo [0, ..., n] (sebbene questo non sia obbligatorio), quindi questa risposta è non del tutto sbagliato, ma impreciso. Tuttavia IMHO la decisione non dovrebbe basarsi su questa "cosa di significato speciale", ma solo su "le chiavi costruiscono approssimativamente un intervallo [0, ..., n]". Sulla base del numero di voti suppongo che la maggior parte dei lettori abbia perso quel punto.
Doc Brown,

28

Pensa a Listcome un array e al Dictionarycome una tabella hash . Utilizzeresti solo Dictionaryse hai bisogno di mappare (o associare) chiavi significative ai valori, mentre un Listunico mappa (o associa) posizioni (o indici) ai valori.

Ad esempio, supponiamo che tu voglia memorizzare un'associazione tra l'età di una persona e la sua altezza. Puoi usare a Dictionary<int, int>per mappare l'età della persona (an int) alla loro altezza (an int):

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

Non è un esempio molto utile, ma il punto è che non saresti in grado di farlo elegantemente con un Listperché dovrebbe archiviare questi valori in posizione.


7
+1 per menzionare che si Listtratta di un ordine , in cui si Dictionarytratta di un'associazione . Se hai bisogno di ottenere i tuoi dati in un determinato ordine ogni volta, o il loro ordine in relazione l'uno con l'altro è importante, a Listè la strada da percorrere. Dictionariestendono ad essere non ordinati e si occupano di mappare chiave -> relazioni di valore.
KChaloux,

2
Infine, quando sai cosa stai cercando, la tabella hash è intorno a O (1), mentre l'array è O (logN) nel migliore dei casi (ordinati e senza duplicati) e O (N) in il caso peggiore.
JensG,

1
+1. Nessun altro sembra aver affrontato il punto secondo cui le liste sono ordinate semanticamente e i dicts sono ricerche semantiche, il che è assolutamente fondamentale , secondo me.
Benjamin Hodgson,

15

Semanticamente, a Dictionary<int, T>e List<T>sono molto simili, entrambi sono contenitori ad accesso casuale del framework .NET. Per utilizzare un elenco in sostituzione di un dizionario, è necessario un valore speciale nel tipo T(come null) per rappresentare gli spazi vuoti nell'elenco. Se Tnon è un tipo nullable come int, è possibile utilizzare int?invece o se si prevede di memorizzare valori positivi, è possibile utilizzare anche un valore speciale come -1 per rappresentare gli slot vuoti.

Quale sceglierai dovrebbe dipendere dall'intervallo dei valori chiave. Se le tue chiavi Dictionary<int, T>sono all'interno di un intervallo intero, senza molte lacune tra loro (ad esempio, 80 valori su [0, ... 100]), allora List<T>sarà più appropriato, poiché l'accesso per indice è più veloce e in questo caso c'è meno memoria e tempo in eccesso rispetto a un dizionario.

Se i tuoi valori chiave sono 100 intvalori da un intervallo come [0, ..., 1000000], allora una List<T>memoria ha bisogno di contenere 1000000 valori di T, dove il tuo dizionario avrà solo bisogno di memoria in un ordine di grandezza intorno a 100 valori di T, 100 valori di int (più un sovraccarico, in realtà si aspettano circa 2 volte la memoria per memorizzare quei 100 tasti e valori). Quindi, in quest'ultimo caso, un dizionario sarà più appropriato.


6
questa è la differenza importante imho, Dictionary <int, int> può essere sparse
jk.

In tal caso, non possiamo usare List <KeyValuePair <int, int >>? Quale sarebbe meglio per l'attraversamento lineare?
Deepak Mishra,

@DeepakMishra: la differenza principale qui è, con List<KeyValuePair<int,T>>, non è disponibile alcuna operazione di ricerca O (1). In secondo luogo, gli elementi List<KeyValuePair<int,T>>possono avere un ordinamento specifico, indipendente dai loro valori chiave. Se hai bisogno del secondo ma non del primo, List<KeyValuePair<int,T>>o List<Tuple<int,T>>potrebbe essere la scelta migliore. Se hai bisogno di entrambi, c'è anche OrderedDictionary.
Doc Brown,

@DocBrown Quale sarebbe meglio per l'attraversamento lineare (cioè foreach) e l'operazione di inserimento, senza necessità di una ricerca diretta?
Deepak Mishra,

@DeepakMishra: non esiste qualcosa come "generalmente migliore" nello sviluppo del software. Meglio qui potrebbe significare più veloce, migliore da leggere, meno codice da digitare, più facile da estendere per i requisiti imminenti. Ma in generale, smetti di pensarci troppo, implementane uno che risolva correttamente il tuo problema ed è molto semplice ai tuoi occhi , controlla se è abbastanza veloce per il tuo scopo e investici solo più pensieri quando osservi gli svantaggi.
Doc Brown,

6

Come si possono considerare equivalenti?

Il dizionario è scarso e consente inserimenti casuali ma rende un attraversamento in ordine un problema, l'elenco non è scarso e un inserimento fuori ordine è costoso, fornisce intrinsecamente un attraversamento in ordine.

Ci sarebbero pochissime situazioni in cui l'una non fosse drammaticamente superiore all'altra.


2

A parte: altri linguaggi di programmazione si riferiscono a questo tipo di struttura di dati come una mappa, piuttosto che un dizionario.

Se i tuoi dati possono essere definiti in modo significativo come coppie chiave / valore, un dizionario fornirà un accesso molto più veloce se devi trovare un valore usando la sua chiave.

Ad esempio, supponiamo di avere un elenco di clienti. Ogni cliente include dettagli come un nome e un indirizzo e un numero cliente unico. Supponiamo di avere anche un elenco di ordini in fase di elaborazione. Ogni Ordine conterrà i dettagli di ciò che viene effettuato e dovrà includere il numero cliente della persona che lo ha ordinato.

Quando un ordine è pronto per la spedizione, devi trovare l'indirizzo a cui spedire. Se i clienti sono memorizzati come un semplice elenco, è necessario cercare l'intero elenco per trovare il cliente con il numero cliente giusto. Invece, è possibile memorizzare i clienti in un dizionario, con il numero cliente come chiave. Il dizionario ora ti consentirà di estrarre il cliente corretto in un solo passaggio senza alcuna ricerca.


1

Il dizionario utilizza l'hashing per cercare i dati. Un dizionario ha prima calcolato un valore di hash per la chiave e questo valore di hash porta al bucket dei dati di destinazione. Successivamente, ogni elemento nel bucket deve essere verificato per la parità. Ma in realtà l'elenco sarà più veloce del dizionario nella ricerca del primo elemento perché non c'è niente da cercare nel primo passaggio. Ma nel secondo passaggio, l'elenco deve esaminare il primo elemento e quindi il secondo elemento. Quindi ogni passaggio della ricerca richiede sempre più tempo. Più grande è l'elenco, più tempo impiegherà.

Maggiori informazioni su .... Dizionario Vs Elenco con esempio.


-1

Se il codice in questione memorizza due serie di valori correlati, la classe Dictionary fornisce un modo indicizzato di cercare valori tramite una chiave. Se esiste un solo set di valori, ma è necessario accedere a tale set in modo casuale (forse per verificare l'esistenza di una chiave in un set) e i valori sono univoci, un HashSet potrebbe essere la migliore classe di set da utilizzare.


-3

Queste sono grandi risposte che sembrano coprire le basi.

Un'altra considerazione che offrirò è che i dizionari (in C #) sono più complessi dal punto di vista della codifica. Avere elenchi e dizionari nella stessa base di codice rende più difficile mantenere il codice in quanto entrambi i metodi presentano sottili differenze nel modo di eseguire operazioni di base come la ricerca e il marshalling dei dati degli oggetti. La mia prospettiva è che, a meno che non sia necessario un dizionario per qualche motivo giustificabile, utilizzare un elenco.


8
Non sono d'accordo. Il dizionario / mappa è una struttura di dati fondamentale che ogni ingegnere informatico dovrebbe conoscere a fondo. In entrambi i casi: sarebbe necessario un motivo giustificabile per utilizzare qualsiasi struttura di dati; compresa la lista.
Steven Evers,
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.