Quelle est la meilleure façon d'itérer un dictionnaire?

j'ai vu quelques différentes façons d'itérer sur un dictionnaire dans C#. Est-il standard?

2031
demandé sur Uwe Keim 2008-09-26 22:20:06

25 réponses

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
2993
répondu Pablo Fernandez 2017-12-20 23:14:01

si vous essayez d'utiliser un dictionnaire Générique En C # comme vous utiliseriez un tableau associatif dans une autre langue:

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

ou, si vous n'avez besoin que d'itérer sur 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);
}

(notez que le mot-clé var est une option C# 3.0 et plus fonction, vous pouvez également utiliser le type exact de votre les clés/valeurs)

674
répondu Jacob 2015-02-02 19:19:26

dans certains cas, vous pouvez avoir besoin d'un compteur qui peut être fourni par l'implémentation de la boucle. Pour cela, LINQ fournit ElementAt qui permet ce qui suit:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}
112
répondu Maurício Fedatto 2018-07-04 12:25:28

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

du MSDN Dictionary(TKey, TValue) Description de 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);
}
75
répondu J Healy 2018-04-09 10:16:06

en Général, en demandant "la meilleure façon", sans un contexte spécifique, c'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 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.

voie la plus directe

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

en Général, les débutants sont surpris par ordre d'énumération d'un Dictionnaire.

LINQ fournit une syntaxe concise qui permet de spécifier l'ordre (et beaucoup 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 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és par les touches

le voici:

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 " plus simple "(voir ci-dessus)!

56
répondu Stéphane Gourichon 2016-09-23 15:38:47

je dirais que foreach est la voie standard, bien qu'elle dépende évidemment de ce que vous cherchez

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

c'est ce que vous cherchez?

38
répondu George Mauer 2018-05-17 15:59:56

vous pouvez également essayer cela sur les grands dictionnaires pour le traitement multithread.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});
29
répondu Onur 2015-06-11 14:50:43

Il ya beaucoup d'options. Mon préféré est de 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 clés et les Collections de valeurs

22
répondu theo 2018-04-12 10:17:29

j'apprécie cette question a déjà eu beaucoup de réponses, mais je voulais la jeter dans 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 essais, 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 la comparaison une liste était quelque part entre 0.00215043 secondes.

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

Les dictionnaires

sont optimisés pour les recherches, c'est pourquoi j'ai créé deux méthodes. L'un fait simplement un foreach, l'autre itère les clés puis regarde vers le haut.

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 touches et itère au-dessus d'eux à la place (j'ai également essayé de tirer le clés en une chaîne de caractères[] 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";
}

dans cet exemple, le test normal foreach a pris 0,0310062 et la version keys 0,2205441. Charger toutes les clés et itérer 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 touches ici (par ce point j'étais juste curieux):

voici le plus rapide méthode 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 normale foreach exécuter pris 0.2820564 secondes (environ dix fois plus longtemps qu'une seule itération pris - que vous attendez). L'itération sur les touches a pris 2.2249449 secondes.

Modifié Pour Ajouter: La lecture de certaines autres réponses m'a fait me demander ce qui se produirait si j'utilisais le Dictionnaire au lieu du dictionnaire. 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 ?

  • Éviter de parcourir un dictionnaire si vous le pouvez, ils sont sensiblement plus lent que de parcourir un tableau avec les mêmes données.
  • si vous choisissez d'itérer sur un dictionnaire n'essayez pas d'être trop intelligent, bien que plus lent, vous pourriez faire bien pire que d'utiliser la méthode foreach standard.
22
répondu Liath 2018-04-28 12:22:57

vous avez suggéré ci - dessous pour 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;
}

pour info, foreach ne fonctionne pas si la valeur est de type object.

9
répondu George Stocker 2010-05-12 16:01:15

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 faire fonctionner ce code sur les versions inférieures de C#, ajouter System.ValueTuple NuGet package et écrire 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;
    }
}
9
répondu Pavel 2017-10-17 15:18:55

la forme la plus simple pour itérer un dictionnaire:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}
7
répondu Ron 2017-03-13 15:35:17

parfois, si vous n'avez besoin que des valeurs à énumérer, utilisez la collection de valeurs du dictionnaire:

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

rapporté par ce post qui déclare qu'il est la méthode la plus rapide: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html

6
répondu ender 2014-07-02 01:55:08

j'ai trouvé cette méthode dans la documentation pour la classe DictionaryBase sur MSDN:

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

C'était le seul que j'ai pu obtenir fonctionnant correctement dans une classe qui a hérité de la DictionaryBase.

5
répondu 2009-02-17 23:51:39

en utilisant C# 7 , ajouter ce méthode d'extension à n'importe quel projet de votre solution:

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



Et utilisez cette syntaxe simple

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



Ou celui - ci, si vous préférez

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



En remplacement du traditionnel

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

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



La méthode d'extension transforme le KeyValuePair de votre IDictionary<TKey, TValue> en un tuple fortement dactylographié , vous permettant d'utiliser cette nouvelle syntaxe confortable.

il convertit-juste - les entrées de dictionnaire nécessaires à tuples , de sorte qu'il ne convertit pas l'ensemble du dictionnaire en tuples , de sorte qu'il n'y a pas de problèmes de performance liés à cela.

il n'y a qu'un coût mineur appelant la méthode d'extension pour créer un tuple en comparaison avec l'utilisation du KeyValuePair directement, qui ne devrait pas être un problème si vous assignez les KeyValuePair 's propriétés Key et Value à de nouvelles variables de boucle de toute façon.

dans la pratique, cette nouvelle syntaxe convient très bien dans la plupart des cas, sauf pour les scénarios ultra-haute performance de bas niveau, où vous avez encore la possibilité de ne pas l'utiliser à cet endroit précis.

Check this out: MSDN Blog - nouvelles fonctionnalités en C# 7

5
répondu sɐunıɔןɐqɐp 2018-08-01 20:38:35

je vais profiter de .NET 4.0+ et fournir une réponse mise à jour à l'un accepté à l'origine:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}
3
répondu yazanpro 2014-10-01 23:17:52

la méthode standard pour itérer sur un dictionnaire, selon la documentation officielle sur MSDN est:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}
3
répondu Nick 2016-07-28 10:58:55

si vous dites, vous voulez itérer au-dessus de la collection de valeurs par défaut, je crois que vous pouvez mettre en œuvre IEnumerable<>, où T est le type de l'objet de valeurs dans le dictionnaire, et" ceci " est un dictionnaire.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
2
répondu 2008-12-09 04:16:11

à partir de C# 7, vous pouvez déconstruire les objets en variables. Je crois que c'est la meilleure façon d'itérer un dictionnaire.

exemple:

créer une méthode d'extension sur KeyValuePair<TKey, TVal> qui la déconstruit:

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

itérer sur toute Dictionary<TKey, TVal> de la manière suivante

// 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}");
}
2
répondu Domn Werner 2018-07-11 18:05:23
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));
1
répondu Pixar 2015-05-28 15:00:10

voulait juste ajouter mon 2 cent, car la plupart des réponses se rapportent à foreach-boucle. S'il vous plaît, regardez le code suivant:

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

Altught ceci ajoute un appel supplémentaire de '.ToList ()', il pourrait y avoir une légère amélioration des performances (comme indiqué ici foreach vs someList.Foreach () {} ), surtout lorsqu'on travaille avec de grands dictionnaires et qu'on exécute en parallèle n'est pas une option / n'aura pas d'effet du tout.

En outre, s'il vous plaît noter que vous ne serez pas en mesure d'assigner des valeurs à la propriété 'Value' à l'intérieur d'une boucle foreach. D'un autre côté, vous serez en mesure de manipuler la " clé " ainsi, peut-être vous mettant dans le pétrin à l'exécution.

si vous voulez simplement "lire" les clés et les valeurs, vous pouvez également utiliser IEnumerable.Sélectionner.)(

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
1
répondu Alex 2017-05-23 12:34:47

j'ai écrit une extension pour boucler un dictionnaire.

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

alors vous pouvez appeler

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
1
répondu Steven Delrue 2018-06-08 07:07:02

Dictionary< TKey, TValue > C'est une classe de collection générique en c# et il stocke les données dans le format de valeur clé.La clé doit être unique et elle ne peut pas être nulle alors que la valeur peut être dupliquée et nulle.Comme chaque élément dans le dictionnaire est traité comme KeyValuePair < TKey, TValue > structure représentant une clé et sa valeur. et donc nous devrions prendre le type D'élément KeyValuePair< TKey, TValue> pendant l'itération de l'élément. En voici un exemple.

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
répondu Sheo Dayal Singh 2018-04-16 11:25:37

en plus des postes les plus élevés où il ya une discussion entre l'utilisation de

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

ou

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

le plus complet est le suivant parce que vous pouvez voir le type de dictionnaire à partir de l'initialisation, kvp est 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
}
0
répondu BigChief 2018-08-19 20:50:39

dictionnaires sont des listes spéciales, alors que chaque valeur dans la liste a une clé qui est aussi une variable. Un bon exemple de dictionnaire est un annuaire téléphonique.

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

Notez que lors de la définition d'un dictionnaire, nous devons fournir un générique la définition de deux types: le type de la clé et le type de la valeur. Dans ce cas, la clé est une chaîne tandis que la valeur est un entier.

Il y a aussi deux façons d'ajouter une valeur unique au dictionnaire, soit en utilisant l'opérateur des crochets ou en utilisant la méthode Add.

pour vérifier si un dictionnaire possède une certaine clé, nous pouvons utiliser la méthode 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"]);
}

pour supprimer un élément d'un dictionnaire, nous pouvons utiliser la méthode Supprimer. Enlever un élément d'un dictionnaire par sa clé est rapide et très efficace. Lors de la suppression d'un élément d'une liste en utilisant sa valeur, le processus est lent et inefficace, contrairement au dictionnaire Supprimer fonction.

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

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);
-2
répondu Amit Kumar Verma 2018-03-15 14:19:14