Domanda Qual è il modo migliore per scorrere su un dizionario?


Ho visto alcuni modi diversi per scorrere su un dizionario in C #. C'è un modo standard?


1944
2017-09-26 18:20


origine


risposte:


foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

2892
2017-09-26 18:22



Se stai cercando di utilizzare un dizionario generico in C # come si usa un array associativo in un'altra lingua:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

Oppure, se hai solo bisogno di iterare sulla collezione di chiavi, usa

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

E infine, se sei interessato solo ai valori:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(Prendi nota che il var parola chiave è un C # 3.0 opzionale e funzionalità di cui sopra, si potrebbe anche utilizzare il tipo esatto delle vostre chiavi / valori qui)


643
2017-09-26 18:22



In alcuni casi potrebbe essere necessario un contatore che può essere fornito dall'implementazione del ciclo. Per questo, LINQ fornisce ElementAt che abilita quanto segue:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

107
2018-03-10 20:44



Dipende se stai cercando le chiavi o i valori ...

Da MSDN Dictionary(TKey, TValue) Descrizione della classe:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}

74
2017-09-26 18:27



In generale, chiedere "il modo migliore" senza un contesto specifico è come chiedere qual è il colore migliore.

Da un lato, ci sono molti colori e non c'è il miglior colore. Dipende dal bisogno e spesso anche dal gusto.

D'altra parte, ci sono molti modi per scorrere su un dizionario in C # e non c'è il modo migliore. Dipende dal bisogno e spesso anche dal gusto.

Il modo più diretto

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Se hai bisogno solo del valore (permette di chiamarlo item, più leggibile di kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

Se hai bisogno di un ordine specifico

Generalmente, i principianti sono sorpresi sull'ordine di enumerazione di un dizionario.

LINQ fornisce una sintassi concisa che consente di specificare l'ordine (e molte altre cose), ad esempio:

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Anche in questo caso potresti aver bisogno solo del valore. LINQ fornisce anche una soluzione concisa per:

  • iterare direttamente sul valore (permette di chiamarlo item, più leggibile di kvp.Value)
  • ma ordinati per le chiavi

Ecco qui:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

Ci sono molti altri casi d'uso del mondo reale che puoi fare da questi esempi. Se non hai bisogno di un ordine specifico, attenersi semplicemente al "modo più diretto" (vedi sopra)!


55
2017-08-10 11:15



Direi che foreach è il modo standard, anche se ovviamente dipende da cosa stai cercando

foreach(var kvp in my_dictionary) {
  ...
}

E 'quello che stai cercando?


36
2017-09-26 18:22



Puoi anche provare questo su grandi dizionari per l'elaborazione multithread.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

27
2018-06-11 13:32



Ci sono molte opzioni. Il mio preferito è KeyValuePair

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

Puoi anche utilizzare le raccolte di chiavi e valori


22
2017-09-26 18:22



Apprezzo che questa domanda abbia già avuto molte risposte, ma ho voluto lanciare una piccola ricerca.

L'iterazione su un dizionario può essere piuttosto lenta se confrontata con l'iterazione su qualcosa come un array. Nei miei test un'iterazione su un array ha richiesto 0,015003 secondi mentre un'iterazione su un dizionario (con lo stesso numero di elementi) ha impiegato 0,0365073 secondi per 2,4 volte il tempo! Anche se ho visto differenze molto più grandi. Per fare un confronto una lista era da qualche parte nel mezzo a 0.00215043 secondi.

Tuttavia, è come paragonare mele e arance. Il mio punto è che iterare sui dizionari è lento.

I dizionari sono ottimizzati per le ricerche, quindi con questo in mente ho creato due metodi. Uno semplicemente fa un foreach, l'altro itera le chiavi quindi alza lo sguardo.

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

Questo carica le chiavi e scorre su di esse (ho anche provato a tirare le chiavi in ​​una stringa [] ma la differenza era trascurabile.

public static string Keys(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var key in dictionary.Keys)
    {
        value = dictionary[key];
        count++;
    }

    return "Keys";
}

Con questo esempio, il normale test foreach ha richiesto 0,0310062 e la versione delle chiavi ha richiesto 0,2205441. Il caricamento di tutte le chiavi e l'iterazione su tutte le ricerche è chiaramente molto più lento!

Per un test finale ho eseguito la mia iterazione dieci volte per vedere se ci sono dei benefici nell'usare le chiavi qui (a questo punto ero solo curioso):

Ecco il metodo RunTest se questo ti aiuta a visualizzare cosa sta succedendo.

private static string RunTest<T>(T dictionary, Func<T, string> function)
{            
    DateTime start = DateTime.Now;
    string name = null;
    for (int i = 0; i < 10; i++)
    {
        name = function(dictionary);
    }
    DateTime end = DateTime.Now;
    var duration = end.Subtract(start);
    return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}

Qui la normale run foreach ha richiesto 0,2820564 secondi (circa dieci volte di più rispetto a una singola iterazione, come previsto). L'iterazione sui tasti ha richiesto 2.224.9449 secondi.

Modificato per aggiungere: Leggere alcune delle altre risposte mi ha fatto dubitare di cosa sarebbe successo se avessi usato Dizionario anziché Dizionario. In questo esempio la matrice ha impiegato 0,0120024 secondi, l'elenco 0,0185037 secondi e il dizionario 0,0465093 secondi. È ragionevole aspettarsi che il tipo di dati faccia la differenza su quanto più lento è il dizionario.

Quali sono le mie conclusioni?

  • Evitare di scorrere su un dizionario, se possibile, sono sostanzialmente più lento di iterare su un array con gli stessi dati in esso contenuti.
  • Se si sceglie di eseguire iterazioni su un dizionario, non cercare di essere troppo intelligente, anche se è più lento fare molto peggio dell'utilizzo del metodo standard foreach.

22
2017-07-30 10:54



Hai suggerito di seguito per iterare

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

Cordiali saluti, foreach non funziona se il valore è di tipo oggetto.


10
2017-10-28 20:49