Question Quelle est la meilleure façon de parcourir un dictionnaire?


J'ai vu quelques façons différentes de parcourir un dictionnaire en C #. Y a-t-il un moyen standard?


1944
2017-09-26 18:20


origine


Réponses:


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

2892
2017-09-26 18:22



Si vous essayez d'utiliser un dictionnaire générique en C # comme si vous utilisiez un tableau associatif dans une autre langue:

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

Ou, si vous avez seulement besoin de parcourir la collection de clés, utilisez

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

Et enfin, si vous êtes seulement intéressé par les valeurs:

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

(Prenez note que le var mot-clé est une fonctionnalité optionnelle C # 3.0 et ci-dessus, vous pouvez également utiliser le type exact de vos clés / valeurs ici)


643
2017-09-26 18:22



Dans certains cas, vous pouvez avoir besoin d'un compteur qui peut être fourni par l'implémentation for-loop. Pour cela, LINQ fournit ElementAt ce qui permet:

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



Cela dépend si vous êtes après les clés ou les valeurs ...

Depuis le MSDN Dictionary(TKey, TValue) Description de la 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



Généralement, demander "la meilleure façon" sans un contexte spécifique est comme demander quelle est la meilleure couleur.

D'une part, il y a beaucoup de couleurs et il n'y a pas de meilleure couleur. Cela dépend du besoin et souvent aussi du goût.

D'un autre côté, il y a plusieurs façons d'itérer sur un dictionnaire en C # et il n'y a pas de meilleure façon. Cela dépend du besoin et souvent aussi du goût.

Moyen le plus simple

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

Si vous n'avez besoin que de la valeur (permet de l'appeler item, plus lisible que kvp.Value).

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

Si vous avez besoin d'un ordre de tri spécifique

Généralement, les débutants sont surpris de l'ordre de l'énumération du Dictionnaire.

LINQ fournit une syntaxe concise qui permet de spécifier l'ordre (et bien d'autres choses), par exemple:

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

Encore une fois, vous pourriez avoir seulement besoin de la valeur. LINQ fournit également une solution concise pour:

  • itérer directement sur la valeur (permet de l'appeler item, plus lisible que kvp.Value)
  • mais trié par les touches

C'est ici:

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

Il y a beaucoup plus de cas d'utilisation dans le monde réel que vous pouvez faire à partir de ces exemples. Si vous n'avez pas besoin d'une commande spécifique, il suffit de s'en tenir à la "manière la plus simple" (voir ci-dessus)!


55
2017-08-10 11:15



Je dirais que foreach est la façon standard, bien que cela dépende évidemment de ce que vous cherchez

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

Est-ce ce que vous cherchez?


36
2017-09-26 18:22



Vous pouvez également essayer ceci sur de grands dictionnaires pour le traitement multithread.

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

27
2018-06-11 13:32



Il y a plein d'options. Mon préféré est KeyValuePair

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

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

Vous pouvez également utiliser les collections de clés et de valeurs


22
2017-09-26 18:22



J'apprécie cette question a déjà eu beaucoup de réponses mais je voulais jeter un peu de recherche.

Itérer sur un dictionnaire peut être plutôt lent par rapport à itérer sur quelque chose comme un tableau. Dans mes tests, une itération sur un tableau a pris 0.015003 secondes alors qu'une itération sur un dictionnaire (avec le même nombre d'éléments) a pris 0.0365073 secondes soit 2.4 fois plus longtemps! Bien que j'ai vu des différences beaucoup plus grandes. Pour comparaison, une liste se situait quelque part entre 0,00215043 secondes.

Cependant, c'est comme comparer des pommes et des oranges. Mon point est que l'itération sur les dictionnaires est lente.

Les dictionnaires sont optimisés pour les recherches, donc dans cet esprit, j'ai créé deux méthodes. On fait simplement une foreach, l'autre itère les clefs puis lève les yeux.

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

    return "Normal";
}

Celui-ci charge les clefs et itère sur eux (j'ai aussi essayé de tirer les clefs dans une corde [] mais la différence était négligeable.

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";
}

Avec cet exemple, le test foreach normal a pris 0,0310062 et la version des clés a pris 0,2205441. Le chargement de toutes les clés et l'itération sur toutes les recherches est clairement beaucoup plus lent!

Pour un test final, j'ai effectué mon itération dix fois pour voir s'il y a des avantages à utiliser les clés ici (à ce stade, j'étais juste curieux):

Voici la méthode RunTest si cela vous aide à visualiser ce qui se passe.

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

Ici, la course foreach normale a pris 0.2820564 secondes (environ dix fois plus longue qu'une seule itération a pris - comme vous vous en doutez). L'itération sur les clés a pris 2.2249449 secondes.

Edité pour ajouter: En lisant certaines des autres réponses, je me suis demandé ce qui se passerait si j'utilisais Dictionary à la place du Dictionary. Dans cet exemple, le tableau a pris 0.0120024 secondes, la liste 0.0185037 secondes et le dictionnaire 0.0465093 secondes. Il est raisonnable de s'attendre à ce que le type de données fasse une différence sur la lenteur du dictionnaire.

Quelles sont mes conclusions?

  • Évitez d'itérer sur un dictionnaire si vous le pouvez, ils sont sensiblement plus lents que d'itérer sur un tableau contenant les mêmes données.
  • Si vous choisissez de parcourir un dictionnaire, n'essayez pas d'être trop intelligent, bien que plus lent, vous pourriez faire pire que d'utiliser la méthode foreach standard.

22
2017-07-30 10:54



Vous avez suggéré ci-dessous d'itérer

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

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

FYI, foreach ne fonctionne pas si la valeur est de type objet.


9
2017-10-28 20:49



Avec .NET Framework 4.7 on peut utiliser décomposition

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

Pour que ce code fonctionne sur les versions C # inférieures, ajoutez System.ValueTuple NuGet package et écris quelque part

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

8
2017-10-17 15:18