Differenza tra Lookup () e Dizionario (Of list ())


165

Sto cercando di capire quali strutture di dati sono le più efficienti e quando / dove utilizzare quali.

Ora, potrebbe essere che semplicemente non capisco abbastanza bene le strutture, ma come è ILookup(of key, ...)diverso da un Dictionary(of key, list(of ...))?

Inoltre, dove vorrei utilizzare un ILookupe dove sarebbe più efficiente in termini di velocità del programma / memoria / accesso ai dati, ecc.?


1
si potrebbe anche voler vedere ciò che è il punto di vista del teleobiettivo
nawfal

Risposte:


255

Due differenze significative:

  • Lookupè immutabile. Yay :) (Almeno, credo che la Lookupclasse concreta sia immutabile e l' ILookupinterfaccia non fornisca alcun membro mutante. Potrebbero esserci altre implementazioni mutabili, ovviamente.)
  • Quando si cerca una chiave che non è presente in una ricerca, si ottiene indietro una sequenza vuota invece di a KeyNotFoundException. (Quindi non c'è TryGetValue, AFAICR.)

È probabile che siano equivalenti in termini di efficienza: la ricerca potrebbe usare un Dictionary<TKey, GroupingImplementation<TValue>>dietro le quinte, per esempio. Scegli tra loro in base alle tue esigenze. Personalmente trovo che la ricerca di solito sia più adatta di unaDictionary<TKey, List<TValue>> , principalmente a causa dei primi due punti sopra.

Si noti che come dettaglio di implementazione, la cui implementazione concreta IGrouping<,>viene utilizzata per i valori implementati IList<TValue>, il che significa che è efficiente da usare con Count(), ElementAt()ecc.


Se una ricerca di chiavi inesistente risulta in una sequenza vuota anziché in un'eccezione, allora non può essere utilizzata come immagine di raccolta per scopi generici. Va bene nel caso di una collezione immutabile che è un sottoprodotto di query linq.
nawfal,

@nawfal - questo è esattamente ciò che cerca. Da msdn : "È possibile creare un'istanza di una ricerca <TKey, TElement> chiamando ToLookup su un oggetto che implementa IEnumerable <T>."
Niall Connaughton,

50

Interessante che nessuno abbia dichiarato la differenza maggiore effettiva (presa direttamente da MSDN ):

Una ricerca ricorda un dizionario. La differenza è che un dizionario mappa le chiavi su singoli valori, mentre una ricerca mappa le chiavi su raccolte di valori.


51
Controlla la domanda: si tratta della differenza tra una ricerca <TKey, TValue> e un dizionario <TKey, List <TValue>>, quindi quella differenza è già abbastanza esplicita.
Martao,

5
@Martao alcune persone trovano questa domanda quando cercano su Google di capire la differenza tra ricerche e dizionari. Questa risposta è davvero utile.
Jakubiszon,

34

Sia a Dictionary<Key, List<Value>>che Lookup<Key, Value>logicamente possono contenere i dati organizzati in modo simile ed entrambi sono dello stesso ordine di efficienza. La differenza principale è che a Lookupè immutabile: non haAdd() metodi né costruttori pubblici (e come menzionato Jon puoi interrogare una chiave inesistente senza eccezioni e avere la chiave come parte del raggruppamento).

Quanto a quale usi, dipende davvero da come li vuoi usare. Se stai mantenendo una mappa di chiavi per più valori che viene costantemente modificata, allora Dictionary<Key, List<Value>>probabilmente è meglio poiché è mutabile.

Se, tuttavia, si dispone di una sequenza di dati e si desidera solo una vista di sola lettura dei dati organizzati per chiave, una ricerca è molto semplice da costruire e fornisce un'istantanea di sola lettura.


11

La differenza principale tra an ILookup<K,V>e a Dictionary<K, List<V>>è che un dizionario è mutabile; puoi aggiungere o rimuovere chiavi e anche aggiungere o rimuovere elementi dall'elenco che hai cercato. An ILookupè immutabile e non può essere modificato una volta creato.

L'implementazione di base di entrambi i meccanismi sarà la stessa o simile, quindi la loro velocità di ricerca e il loro ingombro di memoria saranno approssimativamente gli stessi.


1
@JohnBustos In termini di prestazioni, no. È puramente logico. Puoi passare riferimenti alla struttura attorno a un non preoccuparti che qualcun altro la modifichi da sotto di te. Puoi fare ipotesi sul fatto che è immutabile che non puoi se fosse mutabile.
Servito il

Grazie, Servy, questo è un ottimo punto quando si passano spesso in rassegna tante variabili ByRef - Almeno questa di cui sei sicuro non può essere modificata. Grazie!
John Bustos,

2
@JohnBustos Tieni presente che il metodo predefinito per passare un parametro di metodo è in base al valore, devi aggiungere esplicitamente byref ed è qualcosa che dovrebbe essere fatto abbastanza raramente. Queste strutture di dati sono classi, che li rende tipi di riferimento, quindi passare il valore è il valore del riferimento, motivo per cui passarlo a un altro metodo può causare cambiamenti visibili al chiamante.
Servito il

Grazie, Servy, che mi apre una nuova lattina di worm in termini di ciò che ho fatto :), ma capisco quello che stai dicendo. Grazie!!
John Bustos,

Sotto le copertine sai se Lookup usa hashbucket per la chiave?
paparazzo,

10

Un'altra differenza non ancora menzionata è che Lookup () supporta le chiavi null :

La classe di ricerca implementa l'interfaccia ILookup. La ricerca è molto simile a un dizionario, tranne per il fatto che più valori possono essere associati alla stessa chiave e sono supportate chiavi null.


4

Quando l'eccezione non è un'opzione, andare a cercare

Se stai cercando di ottenere una struttura efficiente come un Dictionaryma non sai con certezza che non ci sono chiavi duplicate in input, Lookupè più sicuro.

Come menzionato in un'altra risposta, supporta anche le chiavi null e restituisce sempre un risultato valido quando viene eseguita una query con dati arbitrari, quindi appare più resistente all'input sconosciuto (meno incline del dizionario per sollevare eccezioni).

Ed è particolarmente vero se lo confronti con la System.Linq.Enumerable.ToDictionaryfunzione:

// won't throw
new[] { 1, 1 }.ToLookup(x => x); 

// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);

L'alternativa sarebbe quella di scrivere il proprio codice duplicato di gestione delle chiavi all'interno di a foreach ciclo.

Considerazioni sulle prestazioni, Dizionario: un chiaro vincitore

Se non hai bisogno di un elenco e gestirai un numero enorme di elementi Dictionary(o anche la tua struttura personalizzata personalizzata) sarebbe più efficiente:

        Stopwatch stopwatch = new Stopwatch();
        var list = new List<string>();
        for (int i = 0; i < 5000000; ++i)
        {
            list.Add(i.ToString());
        }
        stopwatch.Start();
        var lookup = list.ToLookup(x => x);
        stopwatch.Stop();
        Console.WriteLine("Creation: " + stopwatch.Elapsed);

        // ... Same but for ToDictionary
        var lookup = list.ToDictionary(x => x);
        // ...

Come Lookupdeve mantenere un elenco di elementi per ogni tasto, è più lento del Dizionario (circa 3 volte più lento per un numero enorme di elementi)

Velocità di ricerca: Creazione: 00: 00: 01.5760444

Velocità del dizionario: Creazione: 00: 00: 00.4418833

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.