Domanda

Ho visto un paio di modi diversi per eseguire iterazioni su un dizionario in C#.C'è un modo standard?

È stato utile?

Soluzione

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

Altri suggerimenti

Se stai cercando di usare un dizionario generico in C # come se usassi 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);
}

Infine, se sei interessato solo ai valori:

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

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

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

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

Dipende dal fatto che tu stia 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);
}

Generalmente, chiedendo " 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 c'è 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 (consente di chiamarlo item, più leggibile di kvp.Value).

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

Se hai bisogno di un ordinamento specifico

In genere, 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 a:

  • itera direttamente sul valore (consente di chiamarlo <=>, più leggibile di <=>)
  • ma ordinati per chiavi

Eccolo:

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 è necessario un ordine specifico, attenersi alla & Quot; la via più semplice & Quot; (vedi sopra)!

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

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

È quello che stai cercando?

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

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

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

Apprezzo questa domanda ha già avuto un sacco di risposte, ma ho voluto gettare in un po ' di ricerca.

Iterare su un dizionario può essere piuttosto lento se confrontato con l'iterazione su qualcosa come un array.Nel mio test di un'iterazione su un array preso 0.015003 secondi, mentre un'iterazione su un dizionario (con lo stesso numero di elementi), ha preso 0.0365073 secondi 2,4 volte più a lungo!Anche se non ho visto grandi differenze.Per il confronto di un Elenco è stato da qualche parte in mezzo a 0.00215043 secondi.

Tuttavia, che è come paragonare mele e arance.Il mio punto è che la ripetizione su dizionari, è lento.

I dizionari sono ottimizzati per le ricerche, quindi, con questo in mente, ho creato due metodi.Uno semplicemente non fa un foreach, l'altro ripete le chiavi di ricerca.

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 loro invece (ho fatto anche provare a tirare le chiavi in una stringa [], ma la differenza è 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 foreach test ha preso 0.0310062 e le chiavi versione ha preso 0.2205441.Il caricamento di tutti i tasti e scorrere tutte le ricerche è chiaramente MOLTO più lento!

Per un ultimo test che ho eseguito il mio iterazione dieci volte per vedere se ci sono vantaggi ad usare i tasti qui (da questo punto ero solo curioso di sapere):

Ecco il RunTest metodo che consente di visualizzare ciò che 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 il normale foreach corsa ha preso 0.2820564 secondi (circa dieci volte di più di una singola iterazione preso - come ci si aspetterebbe).L'iterazione le chiavi prese 2.2249449 secondi.

Edito Per Aggiungere: Leggendo alcune risposte mi domanda cosa succederebbe se ho usato il Dizionario di Dizionario.In questo esempio, l'array ha preso 0.0120024 secondi, l'elenco 0.0185037 secondi e il dizionario 0.0465093 secondi.È ragionevole aspettarsi che il tipo di dati che fa la differenza su quanto di più lento il dizionario è.

Quali sono le mie Conclusioni?

  • Evitare la ripetizione su un dizionario, se è possibile, sono sostanzialmente più lento scorrere un array con gli stessi dati.
  • Se si sceglie di eseguire iterazioni su un dizionario, non cercare di essere troppo intelligente, anche se più lenta si potrebbe fare molto peggio di utilizzo standard metodo foreach.

C # 7.0 introdotto Decostruttori e se stai utilizzando l'applicazione .NET Core 2.0+ , la struttura KeyValuePair<> include già un Deconstruct() per te. 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

Hai suggerito di seguito 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, foreach non funziona se il valore è di tipo object.

Con .NET Framework 4.7 si può usare 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 package e 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;
    }
}

Modulo più semplice per iterare un dizionario:

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

Usando 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 KeyValuePair del tuo IDictionary<TKey, TValue> in un tuple fortemente tipizzato, permettendoti di usare questa nuova comoda sintassi.

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

C'è solo un piccolo costo per chiamare il metodo di estensione per creare un Value rispetto all'uso di <=> direttamente, che NON dovrebbe essere un problema se si stanno assegnando le proprietà <=> e <=> alle nuove variabili di loop comunque.

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 utilizzarla in quel punto specifico.

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

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

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.

Trarrò vantaggio da .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
}

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
}

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 su KeyValuePair<TKey, TVal> che lo decostruisce:

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey, out TVal val)
{
   key = pair.Key;
   val = 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}");
}

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

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

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

Volevo solo aggiungere il mio 2 cent, poiché la maggior parte delle risposte si riferisce a foreach-loop. 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 si esegue in parallelo non è un'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', probabilmente mettendoti nei guai in fase di esecuzione.

Quando vuoi solo " leggi " Chiavi e valori, è possibile utilizzare anche IEnumerable.Select ().

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

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

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

dizionario lt &; TKey, & # 8194; TValue & Gt; È una classe di raccolta generica in c # e memorizza i dati nel formato del valore-chiave.Key deve essere univoco e non può essere nullo mentre il valore può essere duplicato e nullo. Poiché ogni elemento nel dizionario è trattato come KeyValuePair < TKey, & # 8194; TValue & Gt; struttura che rappresenta una chiave e il suo valore. e quindi dovremmo prendere il tipo di elemento KeyValuePair < & TKey, # 8194; & TValue gt; 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);
}

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

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
}

più completo è il seguente perché puoi vedere 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
}

I dizionari sono liste speciali, mentre ogni valore nella lista ha una chiave    che è anche una variabile. Un buon esempio di dizionario è una rubrica.

   Dictionary<string, long> phonebook = new Dictionary<string, long>();
    phonebook.Add("Alex", 4154346543);
    phonebook["Jessica"] = 4159484588;

Si noti che quando si definisce un dizionario, è necessario fornire un generico    definizione con due tipi: il tipo di chiave e il tipo di valore. In questo caso, la chiave è una stringa mentre il valore è un numero intero.

Esistono anche due modi per aggiungere un singolo valore al dizionario, usando l'operatore parentesi quadre o usando il metodo Aggiungi.

Per verificare se un dizionario contiene una determinata chiave, possiamo usare il metodo ContainsKey:

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

if (phonebook.ContainsKey("Alex"))
{
    Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}

Per rimuovere un elemento da un dizionario, possiamo usare il metodo Rimuovi. La rimozione di un elemento da un dizionario tramite la sua chiave è rapida e molto efficiente. Quando si rimuove un elemento da un elenco usando il suo valore, il processo è lento e inefficiente, a differenza della funzione Rimuovi dizionario.

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top