J'ai vu différentes façons de parcourir un dictionnaire en C #. Y a-t-il un moyen standard?
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
Si vous essayez d'utiliser un dictionnaire générique en C #, utilisez un tableau associatif dans une autre langue:
foreach(var item in myDictionary)
{
foo(item.Key);
bar(item.Value);
}
Ou, si vous devez seulement parcourir la collection de clés, utilisez
foreach(var item in myDictionary.Keys)
{
foo(item);
}
Et enfin, si vous ne vous intéressez qu'aux valeurs:
foreach(var item in myDictionary.Values)
{
foo(item);
}
(Notez que le mot clé var
est une fonctionnalité facultative de C # 3.0 et ultérieure, vous pouvez également utiliser le type exact de vos clés/valeurs ici.)
Dans certains cas, vous aurez peut-être besoin d'un compteur fourni par l'implémentation à boucle forée. 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;
}
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);
}
Généralement, demander "la meilleure façon" sans contexte spécifique revient à 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 du goût.
D'autre part, il existe de nombreuses façons de parcourir un dictionnaire en C # et il n'y a pas de meilleure façon. Cela dépend du besoin et souvent du goût.
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
Si vous avez seulement besoin de la valeur (permet de l'appeler item
, plus lisible que kvp.Value
).
foreach (var item in items.Values)
{
doStuff(item)
}
En règle générale, les débutants sont surpris par l'ordre d'énumération d'un 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 n'aurez peut-être besoin que de la valeur. LINQ fournit également une solution concise pour:
item
, plus lisible que kvp.Value
)C'est ici:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
doStuff(item)
}
Il existe de nombreux autres cas d'utilisation réels que vous pouvez utiliser à partir de ces exemples. Si vous n'avez pas besoin d'une commande spécifique, tenez-vous-en au "moyen le plus direct" (voir ci-dessus)!
Je dirais que foreach est la méthode standard, bien que cela dépende évidemment de ce que vous recherchez.
foreach(var kvp in my_dictionary) {
...
}
Est-ce ce que vous cherchez?
Vous pouvez également essayer ceci sur de gros dictionnaires pour un traitement multithread.
dictionary
.AsParallel()
.ForAll(pair =>
{
// Process pair.Key and pair.Value here
});
Il y a plein d'options. Mon préféré est par 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
J'apprécie que cette question ait déjà suscité beaucoup de réponses, mais je voulais lancer un peu de recherche.
Itérer sur un dictionnaire peut être assez lent par rapport à itérer sur quelque chose comme un tableau. Dans mes tests, une itération sur un tableau prenait 0,015003 secondes alors qu'une itération sur un dictionnaire (avec le même nombre d'éléments) prenait 0,0365073 secondes, soit 2,4 fois plus longtemps! Bien que j'ai vu des différences beaucoup plus grandes. À titre de comparaison, une liste se situait quelque part entre 0,00215043 seconde.
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 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 clés et les itère à la place (j'ai également essayé de tirer les clés dans une chaîne [] 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 foreach normal prenait 0.0310062 et la version de la clé prenait 0.2205441. Charger toutes les clés et parcourir toutes les recherches est clairement beaucoup plus lent!
Pour un dernier test, j'ai effectué mon itération dix fois pour voir s'il y avait un quelconque avantage à utiliser les clés ici (à ce stade, j'étais simplement 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, le cycle normal de chaque opération a pris 0,2820564 secondes (environ dix fois plus longtemps qu’une seule itération - comme on pouvait s’y attendre). L'itération sur les clés a pris 2,2249449 secondes.
Edited To Add: La lecture de certaines des autres réponses m'a amené à me demander ce qui se passerait si j'utilisais Dictionary au lieu de Dictionary. Dans cet exemple, le tableau prenait 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 influe sur la lenteur du dictionnaire.
Quelles sont mes conclusions?
C # 7. introduit Déconstructeurs et si vous utilisez . NET Core 2.0+ Application, la structure KeyValuePair<>
inclut déjà une Deconstruct()
pour vous. Alors tu peux faire:
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}");
}
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.
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 écrivez 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;
}
}
En utilisant C # 7 , ajoutez cette 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'
}
Au lieu 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 typé, vous permettant d'utiliser cette nouvelle syntaxe confortable.
Il convertit -just- les entrées de dictionnaire requises en tuples
. Il ne convertit donc PAS le dictionnaire entier en tuples
. Il n'y a donc pas de problème de performances lié à cela.
L'appel de la méthode d'extension pour créer un Tuple
par rapport à l'utilisation directe du KeyValuePair
n'implique, de manière coûteuse, qu'un problème si vous affectez de toute façon les propriétés KeyValuePair
à Key
et Value
à de nouvelles variables de boucle.
En pratique, cette nouvelle syntaxe convient très bien dans la plupart des cas, à l'exception des scénarios de performances ultra-hautes performances de bas niveau, où vous avez toujours la possibilité de simplement ne pas l'utiliser à cet endroit spécifique.
Découvrez ceci: Blog MSDN - Nouvelles fonctionnalités de C # 7
La forme la plus simple pour itérer un dictionnaire:
foreach(var item in myDictionary)
{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}
Parfois, si vous n’avez besoin que d’énumérer les valeurs, utilisez la collection de valeurs du dictionnaire:
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
Signalé par cet article qui déclare que c'est la méthode la plus rapide: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
J'ai trouvé cette méthode dans la documentation de la classe DictionaryBase sur MSDN:
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
C'était le seul que je pouvais obtenir de fonctionner correctement dans une classe héritée de DictionaryBase.
À partir de C # 7, vous pouvez décomposer des objets en variables. Je crois que c'est le meilleur moyen de parcourir un dictionnaire.
Exemple:
Créez 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 tout 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}");
}
La méthode standard pour parcourir un dictionnaire, selon la documentation officielle sur MSDN, est la suivante:
foreach (DictionaryEntry entry in myDictionary)
{
//Read entry.Key and entry.Value here
}
Je vais tirer parti de .NET 4.0+ et fournir une réponse mise à jour à celle initialement acceptée:
foreach(var entry in MyDic)
{
// do something with entry.Value or entry.Key
}
Si par exemple, vous voulez parcourir la collection de valeurs par défaut, je pense que vous pouvez implémenter IEnumerable <>, où T est le type de l'objet de valeurs dans le dictionnaire et "this" est un dictionnaire.
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
Je sais que la question est très ancienne, mais j’ai créé des méthodes d’extension qui pourraient être utiles:
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); }
}
De cette façon, je peux écrire du code comme ceci:
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););
J'ai écrit une extension à boucler sur 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);
}
}
}
Ensuite, vous pouvez appeler
myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
var dictionary = new Dictionary<string, int>
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));
Je voulais juste ajouter mon 2 cent, car la plupart des réponses concernent foreach-loop. S'il vous plaît, jetez un oeil sur 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));
});
Bien que cela 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 lorsque vous travaillez avec Les dictionnaires et l'utilisation en parallèle ne sont pas une option/n'auront aucun effet.
Veuillez également noter que vous ne pourrez pas affecter de valeurs à la propriété 'Value' dans une boucle foreach. D'autre part, vous pourrez également manipuler la "clé", ce qui peut éventuellement vous causer des problèmes lors de l'exécution.
Lorsque vous voulez simplement "lire" des clés et des valeurs, vous pouvez également utiliser IEnumerable.Select ().
var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
Dictionary <TKey, TValue> C'est une classe de collection générique en c # et stocke les données dans le format de valeur de clé.Key doit être unique et ne peut pas être null alors que la valeur peut être dupliquée et nulle. Chaque élément du dictionnaire étant traité comme une structure KeyValuePair <TKey, TValue> représentant une clé et sa valeur. et par conséquent nous devrions prendre le type d'élément KeyValuePair <TKey, TValue> lors de l'itération de l'élément .Ci-dessous, l'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);
}
Les trois méthodes différentes d'itération sur le dictionnaire.
Méthode 1: utilisation de la boucle for
for (int i = 0; i < DemotestDictionary.Count; i++ )
{
int key = i;
string value = DemotestDictionary[i];
// Do something here
}
Méthode 2: utiliser chaque itération
foreach (var entry in DemotestDictionary)
{
int key = entry.Key;
string value = entry.Value;
// Do something here
}
Méthode 3-pour chaque itération à l'aide de KeyValuePair
foreach (KeyValuePair<int, string> entry in DemotestDictionary)
{
int key = entry.Key;
string value = entry.Value;
// Do something here
}