Qual è il modo migliore per scorrere su un dizionario?


2628

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


108
Sono sorpreso che ci siano molte risposte a questa domanda, insieme a una votata 923 volte .. (usa foreach ofcourse) .. Direi, o almeno aggiungerei che se devi iterare su un dizionario, è probabile che tu sia usandolo in modo errato / inappropriato .. Ho dovuto fare questo commento, perché ho visto abusare dei dizionari in modi in cui IMHO non era appropriato ... Sì, ci possono essere rare circostanze quando si itera il dizionario, piuttosto che la ricerca, che è ciò che è progettato per .. Tienilo a mente, prima di chiederti come iterare su un dizionario.
Vikas Gupta,

74
@VikasGupta Cosa consiglieresti di fare qualcosa con una raccolta di coppie chiave-valore quando non sai quali saranno le chiavi?
nasch,

26
@displayName Se vuoi fare qualcosa con ciascuna coppia chiave-valore ma non hai un riferimento alle chiavi da usare per cercare i valori, dovresti scorrere il dizionario, giusto? Stavo solo sottolineando che potrebbero esserci delle volte in cui vorresti farlo, nonostante l'affermazione di Vikas che questo sia di solito un uso errato.
nasch,

35
Dire che è un uso errato implica un'alternativa migliore. Cos'è quella alternativa?
Kyle Delaney,

41
VikasGupta ha torto, posso affermare che dopo molti anni di programmazione C # e C ++ ad alte prestazioni in scenari non teorici. Vi sono infatti casi frequenti in cui si creerebbe un dizionario, si memorizzerebbero coppie chiave-valore univoche e quindi si passerà in rassegna questi valori, che hanno dimostrato di avere chiavi univoche all'interno della raccolta. La creazione di ulteriori raccolte è un modo davvero inefficiente e costoso per evitare l'iterazione del dizionario. Fornisci una buona alternativa come risposta alla domanda che chiarisca il tuo punto di vista, altrimenti il ​​tuo commento è piuttosto privo di senso.
sɐunıɔ ןɐ qɐp

Risposte:


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

29
Che cosa succede se non conosco esattamente il tipo di chiave / valore nel Dizionario. Usare var entryè meglio in quel caso, e quindi ho votato questa risposta su una seconda occhiata invece di quella sopra.
Ozair Kafray il

93
@OzairKafray utilizzando varquando non si conosce il tipo è generalmente una cattiva pratica.
Nate,

52
Questa risposta è superiore perché Pablo non ha utilizzato in modo predefinito il codificatore "var" che utilizza il tipo restituito.
MonkeyWrench,

119
@MonkeyWrench: Meh. Visual Studio sa quale sia il tipo; tutto quello che devi fare è passare il mouse sopra la variabile per scoprirlo.
Robert Harvey,

31
A quanto ho capito, varfunziona solo se il tipo è noto al momento della compilazione. Se Visual Studio conosce il tipo, è anche possibile scoprirlo.
Kyle Delaney,

866

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

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

Oppure, se hai solo bisogno di scorrere la raccolta 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);
}

(Tieni presente che la varparola chiave è una funzione C # 3.0 e superiore opzionale, puoi anche utilizzare qui il tipo esatto di chiavi / valori)


11
la funzione var è più richiesta per il tuo primo blocco di codice :)
nawfal

27
Apprezzo che questa risposta sottolinei che puoi iterare esplicitamente sulle chiavi o sui valori.
Rotsiser Mho,

11
Non mi piace l'uso di var qui. Dato che è solo zucchero sintattico, perché usarlo qui? Quando qualcuno sta cercando di leggere il codice, dovrà saltare il codice per determinare il tipo di myDictionary(a meno che questo non sia il nome effettivo ovviamente). Penso che usare var sia buono quando il tipo è ovvio, ad esempio var x = "some string"ma quando non è immediatamente ovvio penso che sia la codifica pigra che fa male al lettore / revisore del codice
James Wierzba,

8
varsecondo me dovrebbe essere usato con parsimonia. Soprattutto qui, non è costruttivo: il tipo KeyValuePairè probabilmente rilevante per la domanda.
Sinjai,

3
varha uno scopo unico e non credo che sia zucchero "sintattico". Usarlo intenzionalmente è un approccio appropriato.
Joshua K,

159

In alcuni casi potrebbe essere necessario un contatore che può essere fornito dall'implementazione for-loop. A tale scopo, LINQ fornisce ciò ElementAtche consente quanto segue:

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

21
Per usare il metodo '.ElementAt', ricorda: usando System.Linq; Questo non è incluso in FX. classi di test generate automaticamente.
Tinia,

14
Questa è la strada da percorrere se si stanno modificando i valori associati alle chiavi. Altrimenti viene generata un'eccezione quando si modifica e si utilizza foreach ().
Mike de Klerk,

27
Non è ElementAtun'operazione O (n)?
Arturo Torres Sánchez,

162
Questa risposta è completamente immeritevole di così tanti voti. Un dizionario non ha un ordine implicito, quindi l'utilizzo .ElementAtin questo contesto potrebbe portare a bug sottili. Molto più grave è il punto sopra di Arturo. Stai ripetendo i dictionary.Count + 1tempi del dizionario che portano alla complessità O (n ^ 2) per un'operazione che dovrebbe essere solo O (n). Se hai davvero bisogno di un indice (se lo fai, probabilmente stai usando il tipo di raccolta errato in primo luogo), dovresti dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})invece eseguire l'iterazione e non utilizzare .ElementAtall'interno del ciclo.
spender

5
ElementAt - o (n) operazione! Sul serio? Questo è l'esempio di come non dovresti farlo. Questi molti voti?
Mukesh Adhvaryu,

96

Dipende dal fatto che tu stia cercando le chiavi o i valori ...

Dalla Dictionary(TKey, TValue)descrizione della classe MSDN :

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

82

Generalmente, chiedere "il modo migliore" senza un contesto specifico è come chiedere qual è il colore migliore ?

Da un lato, ci sono molti colori e non esiste il colore migliore. Dipende dalla necessità e spesso anche dal gusto.

D'altra parte, ci sono molti modi per scorrere su un dizionario in C # e non esiste un modo migliore. Dipende dalla necessità e spesso anche dal gusto.

Il modo più semplice

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 è necessario un ordinamento specifico

Generalmente, i principianti sono sorpresi dall'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)
}

Ancora una volta potresti aver bisogno solo del valore. LINQ offre anche una soluzione concisa per:

  • iterare direttamente sul valore (permette di chiamarlo item, più leggibile di kvp.Value)
  • ma ordinati per 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 reali che puoi fare da questi esempi. Se non hai bisogno di un ordine specifico, segui il "modo più semplice" (vedi sopra)!


L'ultima dovrebbe essere .Valuese non una clausola select.
Mafii,

@Mafii Sei sicuro? I valori restituiti da OrderBy non sono di tipo KeyValuePair, non hanno Valuecampi. Il tipo esatto che vedo qui è IOrderedEnumerable<KeyValuePair<TKey, TValue>>. Forse intendevi qualcos'altro? Puoi scrivere una riga completa che mostri cosa intendi (e testarlo)?
Stéphane Gourichon,

Penso che questa risposta contenga ciò che intendo: stackoverflow.com/a/141105/5962841 ma correggimi se ho confuso qualcosa
Mafii,

1
@Mafii Rileggi tutta la mia risposta, spiegazioni tra sezioni di codice raccontano il contesto. La risposta che citi è come la seconda sezione di codice nella mia risposta (nessun ordine richiesto). Lì ho appena scritto items.Valuecome hai suggerito. Nel caso della quarta sezione che hai commentato, Select()è un modo per far foreachelencare direttamente i valori nel dizionario anziché le coppie chiave-valore. Se in qualche modo non ti piace Select()in questo caso, potresti preferire la terza sezione di codice. Il punto della quarta sezione è mostrare che è possibile pre-elaborare la raccolta con LINQ.
Stéphane Gourichon,

1
Se lo fai .Keys.Orderby(), ripeterai un elenco di chiavi. Se è tutto ciò di cui hai bisogno, va bene. Se hai bisogno di valori, nel ciclo dovresti interrogare il dizionario su ogni chiave per ottenere il valore. In molti scenari non farà alcuna differenza pratica. In uno scenario ad alte prestazioni, lo farà. Come ho scritto all'inizio della risposta: "ci sono molti modi (...) e non esiste un modo migliore. Dipende dalla necessità e spesso anche dal gusto".
Stéphane Gourichon,

53

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

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

È quello che stai cercando?


42
Uhm, la denominazione dell'elemento "valore" non è piuttosto confusa? In genere useresti una sintassi come "value.Key" e "value.Value", che non è molto intuitiva per chiunque leggerà il codice, soprattutto se non ha familiarità con l'implementazione del .Net Dictionary .
RenniePet,

3
@RenniePet kvpè comunemente utilizzato per denominare le istanze KeyValuePair quando l'iterazione su dizionari e le strutture di dati correlati: foreach(var kvp in myDictionary){....
mbx

37

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

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

8
@WiiMaxx e più importante se questi elementi NON dipendono l'uno dall'altro
Mafii

37

C # 7.0 ha introdotto Deconstructors e se si utilizza l'applicazione .NET Core 2.0+ , la strutturaKeyValuePair<>include già unaDeconstruct()per voi. Quindi puoi fare:

var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
    Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}

inserisci qui la descrizione dell'immagine


5
Se si utilizza .NET Framework, che almeno fino a 4.7.2 non ha Deconstruct su KeyValuePair, provare questo:foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
nwsmith,

29

Apprezzo che questa domanda abbia già avuto molte risposte, ma ho voluto gettare 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 richiesto 0,0365073 secondi che è 2,4 volte più lungo! Anche se ho visto differenze molto più grandi. Per fare un confronto, una lista si trovava da qualche parte tra 0,00215043 secondi.

Tuttavia, è come confrontare mele e arance. Il mio punto è che l'iterazione sui dizionari è lenta.

I dizionari sono ottimizzati per le ricerche, quindi con questo in mente ho creato due metodi. Uno fa semplicemente una foreach, l'altro scorre le chiavi e poi 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 le scorre invece 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 chiavi ha richiesto 0,2205441. Il caricamento di tutti i tasti 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 vantaggi nell'usare i tasti qui (a questo punto ero solo curioso):

Ecco il metodo RunTest se 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 corsa foreach ha richiesto 0,2820564 secondi (circa dieci volte più a lungo di una singola iterazione, come previsto). L'iterazione sui tasti ha richiesto 2,2249449 secondi.

Modificato per aggiungere: la lettura di alcune delle altre risposte mi ha fatto mettere in dubbio cosa succederebbe se usassi Dizionario invece di Dizionario. In questo esempio l'array 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 ?

  • Se possibile, evitare l'iterazione su un dizionario, poiché sono sostanzialmente più lenti rispetto all'iterazione su un array con gli stessi dati.
  • Se scegli di scorrere su un dizionario, non cercare di essere troppo intelligente, anche se più lentamente potresti fare molto peggio che usare il metodo foreach standard.

11
Dovresti misurare con qualcosa come StopWatch invece di DateTime: hanselman.com/blog/…
Anche Mien,

2
potresti descrivere lo scenario di prova, quanti elementi nel tuo dizionario, con quale frequenza hai eseguito lo scenario per calcolare il tempo medio, ...
WiiMaxx,

3
È interessante notare che otterrai risultati diversi a seconda dei dati che hai nel dizionario. Mentre scorre sul dizionario, la funzione Enumeratore deve saltare un sacco di slot vuoti nel dizionario, il che è ciò che lo rende più lento dell'iterazione su un array. Se il dizionario è pieno, ci saranno meno slot vuoti da saltare rispetto a se è mezzo vuoto.
Martin Brown,

26

Ci sono molte opzioni. Il mio preferito è di 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


14

Con .NET Framework 4.7uno si può usare la decomposizione

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

Per far funzionare questo codice su versioni C # inferiori, aggiungi System.ValueTuple NuGet packagee scrivi da qualche parte

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}

9
Questo non è corretto .NET 4.7 ha semplicemente ValueTupleintegrato. È disponibile come pacchetto nuget per le versioni precedenti. Ancora più importante, è necessario C # 7.0+ per Deconstructfar funzionare il metodo come decostruttore var (fruit, number) in fruits.
David Arno,

13

A partire da C # 7, puoi decostruire gli oggetti in variabili. Credo che questo sia il modo migliore per scorrere su un dizionario.

Esempio:

Crea un metodo di estensione KeyValuePair<TKey, TVal>che lo decostruisce:

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}

Scorrere su qualsiasi Dictionary<TKey, TVal>nel modo seguente

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}

10

Di seguito hai suggerito di 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, foreachnon funziona se il valore è di tipo oggetto.


4
Si prega di elaborare: foreachnon funzionerà se quale valore è di tipo object? Altrimenti questo non ha molto senso.
Marc L.

9

Modulo più semplice per iterare un dizionario:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}

9

Utilizzando C # 7 , aggiungi questo metodo di estensione a qualsiasi progetto della tua soluzione:

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in dict)
            yield return (kvp.Key, kvp.Value);
    }
}


E usa questa semplice sintassi

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


O questo, se preferisci

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Al posto del tradizionale

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


Il metodo di estensione trasforma il KeyValuePairtuo IDictionary<TKey, TValue>in un fortemente tipizzatotuple , permettendoti di usare questa nuova sintassi comoda.

Converte -just- le voci del dizionario richieste in tuples, quindi NON converte l'intero dizionario in tuples, quindi non ci sono problemi di prestazioni correlati a quello.

C'è solo un piccolo costo per chiamare il metodo di estensione per la creazione di un tupleconfronto con l'uso KeyValuePairdiretto, che NON dovrebbe essere un problema se si stanno assegnando le KeyValuePairproprietàKey e Valuecomunque le nuove variabili del ciclo.

In pratica, questa nuova sintassi si adatta molto bene alla maggior parte dei casi, ad eccezione degli scenari di prestazioni ultra-alte di basso livello, in cui hai ancora la possibilità di non usarlo in quel punto specifico.

Dai un'occhiata a: Blog MSDN - Nuove funzionalità in C # 7


1
Quale sarebbe la ragione per preferire le tuple "comode" alle coppie chiave-valore? Non vedo un guadagno qui. La tua tupla contiene una chiave e un valore, così come la coppia chiave-valore.
Maarten,

4
Ciao Maarten, grazie per la tua domanda. Il vantaggio principale è la leggibilità del codice senza ulteriori sforzi di programmazione. Con KeyValuePair è necessario utilizzare sempre il modulo kvp.Keye kvp.Valueper utilizzare rispettivamente chiave e valore. Con le tuple hai la flessibilità di nominare la chiave e il valore come desideri, senza usare ulteriori dichiarazioni variabili all'interno del blocco foreach. Ad esempio, è possibile nominare la chiave come factoryNamee il valore come models, che è particolarmente utile quando si ottengono cicli nidificati (dizionari di dizionari): la manutenzione del codice diventa molto più semplice. Basta fare un tentativo! ;-)
sɐunıɔ ןɐ qɐp

7

So che questa è una domanda molto vecchia, ma ho creato alcuni metodi di estensione che potrebbero essere utili:

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }

In questo modo posso scrivere codice in questo modo:

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););

6

A volte se hai solo bisogno di enumerare i valori, usa la raccolta valori del dizionario:

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

Segnalato da questo post che afferma che è il metodo più veloce: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html


+1 per apportare prestazioni. In effetti, l'iterazione sul dizionario stesso include un certo sovraccarico se tutto ciò di cui hai bisogno sono valori. Ciò è dovuto principalmente alla copia di valori o riferimenti nelle strutture KeyValuePair.
Jaanus Varus,

1
Cordiali saluti, l'ultimo test in quel link è il test della cosa sbagliata: misura l'iterazione sulle chiavi, ignorando i valori, mentre i due test precedenti usano il valore.
Crescent Fresh,

5

Ho trovato questo metodo nella documentazione per la classe DictionaryBase su MSDN:

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

Questo è stato l'unico che sono riuscito a far funzionare correttamente in una classe ereditata da DictionaryBase.


3
Questo sembra quando si utilizza la versione non generica di Dictionary ... vale a dire prima di .NET Framework 2.0.
joedotnot,

@ joed0tnot: è la versione non Hashtable
generica

5

foreachè più veloce e se si esegue solo l'iterazione ___.Values, è anche più veloce

inserisci qui la descrizione dell'immagine


1
Perché stai chiamando ContainsKey()nella forversione? Ciò aggiunge un sovraccarico extra che non è presente nel codice con cui stai confrontando. TryGetValue()esiste per sostituire l'esatto modello "se esiste la chiave, ottieni l'elemento con chiave". Inoltre, se dictcontiene un intervallo contiguo di numeri interi da 0a dictCount - 1, sai che l'indicizzatore non può fallire; altrimenti, dict.Keysè ciò che dovresti ripetere. In entrambi i casi, no ContainsKey()/ TryGetValue()necessario. Infine, per favore non pubblicare schermate di codice.
BACON

3

Approfitterò di .NET 4.0+ e fornirò una risposta aggiornata a quella inizialmente accettata:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}

3

Il modo standard per scorrere su un dizionario, secondo la documentazione ufficiale su MSDN è:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}

2

Ho scritto un'estensione per scorrere su un dizionario.

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

Quindi puoi chiamare

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));

Hai definito un ForEachmetodo in cui hai foreach (...) { }... Sembra inutile.
Maarten,

1

Se si dice, si desidera scorrere la raccolta di valori per impostazione predefinita, credo che sia possibile implementare IEnumerable <>, dove T è il tipo di oggetto valore nel dizionario e "this" è un dizionario.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}

1

Come già sottolineato in questa risposta , KeyValuePair<TKey, TValue>implementa un Deconstructmetodo che inizia su .NET Core 2.0, .NET Standard 2.1 e .NET Framework 5.0 (anteprima).

Con questo, è possibile scorrere un dizionario in KeyValuePairmodo agnostico:

var dictionary = new Dictionary<int, string>();

// ...

foreach (var (key, value) in dictionary)
{
    // ...
}

0
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));

2
Ci deve essere più giustificazione / descrizione in questa risposta. Cosa AggregateObjectaggiunge KeyValuePair? Dov'è la "iterazione", come richiesto nella domanda?
Marc L.

Seleziona scorre sul dizionario e ci consente di lavorare su ogni oggetto. Non è così generale foreach, ma l'ho usato molto. La mia risposta meritava davvero un voto negativo?
Pixar

No, Select utilizza l' iterazione per effettuare il risultato, ma non è un iteratore stesso. I tipi di cose per cui foreachè usato iteration ( ) - specialmente le operazioni con effetti collaterali - sono al di fuori dell'ambito di Linq, incluso Select. La lambda non verrà eseguita fino a quando non aggregateObjectCollectionviene effettivamente elencata. Se questa risposta è presa come un "primo percorso" (cioè, usato prima di una scala foreach) incoraggia le cattive pratiche. A seconda della situazione, potrebbero esserci operazioni Linq che sono utili prima di ripetere un dizionario, ma che non rispondono alla domanda come posta.
Marc L.

0

Volevo solo aggiungere il mio 2 centesimi, poiché la maggior parte delle risposte si riferisce a foreach-loop. Per favore, dai un'occhiata al seguente codice:

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//Add some entries to the dictionary

myProductPrices.ToList().ForEach(kvP => 
{
    kvP.Value *= 1.15;
    Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});

Anche se questo aggiunge un ulteriore richiamo di '.ToList ()', potrebbe esserci un leggero miglioramento delle prestazioni (come sottolineato qui foreach vs someList.Foreach () {} ), soprattutto quando si lavora con dizionari di grandi dimensioni e l'esecuzione in parallelo non è no opzione / non avrà alcun effetto.

Inoltre, tieni presente che non sarai in grado di assegnare valori alla proprietà 'Value' all'interno di un ciclo foreach. D'altra parte, sarai anche in grado di manipolare la 'Chiave', mettendoti probabilmente nei guai in fase di esecuzione.

Quando vuoi semplicemente "leggere" chiavi e valori, puoi anche usare IEnumerable.Select ().

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );

5
Copiare l'intera collezione senza motivo non migliorerà le prestazioni. Rallenterà notevolmente il codice, oltre a raddoppiare l'impronta di memoria del codice che non dovrebbe consumare praticamente alcuna memoria aggiuntiva.
Servito il

Evito il metodo "List.ForEach" degli foreacheffetti collaterali: aumenta la visibilità degli effetti collaterali, a cui appartiene.
user2864740

0

Dizionario <TKey, TValue> È una classe di raccolta generica in c # e memorizza i dati nel formato del valore chiave. Il tasto deve essere univoco e non può essere nullo mentre il valore può essere duplicato e nullo. Come ogni elemento nel dizionario è trattato come KeyValuePair <TKey, TValue> struttura che rappresenta una chiave e il suo valore. e quindi dovremmo prendere il tipo di elemento KeyValuePair <TKey, TValue> durante l'iterazione dell'elemento. Di seguito è riportato l'esempio.

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}

0

Se si desidera utilizzare per il ciclo, è possibile effettuare ciò:

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }

Qual è il vantaggio di questo, però? È un codice più lungo di un foreachloop e prestazioni peggiori perché new List<string>(dictionary.Keys)ripeterà i dictionary.Counttempi prima ancora che tu abbia la possibilità di iterarlo da solo. Mettendo da parte il fatto che chiedere "il modo migliore" è soggettivo, non vedo come questo si qualificherebbe né come "modo migliore" o "modo standard" che la domanda cerca. A "Se si desidera utilizzare per il loop ..." Contrasterei con " Non utilizzare un forloop".
BACON,

Se si dispone di una raccolta di grandi dimensioni e le operazioni sono lente in foreach e se la raccolta può cambiare quando si esegue l'iterazione, ti protegge dall'errore "raccolta è cambiata" e questa soluzione offre prestazioni migliori rispetto a ElementAt.
Seçkin Durgay,

Concordo sul fatto che evitare le eccezioni "La raccolta è stata modificata" è una delle ragioni per farlo, sebbene quel caso speciale non sia stato indicato nella domanda e si potrebbe sempre fare foreach (var pair in dictionary.ToArray()) { }. Tuttavia, penso che sarebbe bene chiarire nella risposta gli scenari specifici in cui si vorrebbe usare questo codice e le implicazioni nel farlo.
BACON

sì, hai ragione, ma qui c'è una risposta con ElementAt, ha una reputazione molto alta e ho inserito questa risposta :)
Seçkin Durgay,

-2

semplice con linq

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );

Vedo che stai chiamando ToList()perché ForEach()è definito solo sulla List<>classe, ma perché fare tutto questo invece che solo foreach (var pair in dict) { }? Direi che è ancora più semplice e non ha le stesse implicazioni di memoria / prestazioni. Questa soluzione esatta era già stata proposta in questa risposta da 3,5 anni fa, comunque.
BACON il

Solo per motivi di visualizzazione del codice, potrebbe davvero essere fatto come indicato, volevo solo presentarlo in un modo diverso e nella mia visione più snella, mi scuso per non aver visto la risposta indicata, un abbraccio
Luiz Fernando Corrêa Leite

-4

oltre ai post più alti in cui vi è una discussione tra l'utilizzo

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

o

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

il più completo è il seguente perché è possibile visualizzare il tipo di dizionario dall'inizializzazione, kvp è KeyValuePair

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}

5
La creazione e la copia di un secondo dizionario non è una soluzione valida per la leggibilità del codice. In effetti, direi che renderebbe il codice più difficile da capire perché ora devi chiederti: "Perché l'ultimo ragazzo ha creato un secondo dizionario?" Se vuoi essere più prolisso, usa l'opzione 1.
Matthew Goulart,

Volevo solo mostrarvi che quando declinate prima per ciascuno, l'uso nella foreach è chiaro dalla dichiarazione
BigChief
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.