2009-03-24 14 views
21

Comment énumérer un dictionnaire? Supposons que j'utilise foreach() pour l'énumération de dictionay.Énumération du dictionnaire en C#

Je ne peux pas mettre à jour une paire clé/valeur à l'intérieur de foreach(). Donc je veux une autre méthode.

Répondre

75

Enumérer un dictionnaire soit vous énumérer les valeurs en son sein:

Dictionary<int, string> dic; 

foreach(string s in dic.Values) 
{ 
    Console.WriteLine(s); 
} 

ou les KeyValuePairs

foreach(KeyValuePair<int, string> kvp in dic) 
{ 
    Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value); 
} 

ou les touches

foreach(int key in dic.Keys) 
{ 
    Console.WriteLine(key.ToString()); 
} 

Si vous souhaitez mettre à jour les éléments dans le dictionnaire, vous devez le faire légèrement différemment, car vous ne pouvez pas mettre à jour l'instance en énumérant. Qu'est-ce que vous devez faire est d'énumérer une collection différente qui ne sont pas mis à jour, comme ceci:

Dictionary<int, string> newValues = new Dictionary<int, string>() { 1, "Test" }; 
foreach(KeyValuePair<int, string> kvp in newValues) 
{ 
    dic[kvp.Key] = kvp.Value; // will automatically add the item if it's not there 
} 

Pour supprimer des éléments, faire de la même manière, la collection d'énumérer les éléments que nous voulons supprimer plutôt que le dictionnaire lui-même.

List<int> keys = new List<int>() { 1, 3 }; 
foreach(int key in keys) 
{ 
    dic.Remove(key); 
} 
+0

Ou vous pouvez énumérer les clés. – strager

+0

En effet! Merci d'avoir fait remarquer cela. – Ian

+2

Je m'attendrais à ce que l'énumération des clés soit plus courante que d'énumérer seulement les valeurs (du moins c'est mon expérience), puisque vous pouvez trouver la valeur de la clé assez facilement (c'est le point du dictionnaire). – Wedge

8

Foreach. Il existe trois façons: Vous pouvez énumérer sur la propriété Keys, sur la propriété Values ou sur le dictionnaire même qui est un énumérateur de KeyValuePair<TKey, TValue>.

9

En réponse au problème "Je ne peux pas mettre à jour valeur/clé dans foreach()", vous ne pouvez pas modifier une collection en l'énumérant. J'aborder ce en faisant une copie de la collection Clés:

Dictionary<int,int> dic=new Dictionary<int, int>(); 

//...fill the dictionary 

int[] keys = dic.Keys.ToArray(); 
foreach (int i in keys) 
{ 
    dic.Remove(i); 
} 
+0

Pas besoin de .ToArray() AFAIK. .Keys renvoie un IEnumerable. – strager

+1

sûr, mais si le dictionnaire est modifié dans la boucle, qu'arrive-t-il à cette énumération? ça change, sûrement? – spender

+0

Je ne l'aurais pas pensé. Le dic.Keys retournera un IEnumerable dans ce cas, qui sera toutes les valeurs. Si vous deviez simplement utiliser le IEnumerator à la place, cela pourrait être le cas. – Ian

2

Je viens de répondre de la même (mis à jour) question des listes, voici donc la même chose pour les dictionnaires.

public static void MutateEach(this IDictionary<TKey, TValue> dict, Func<TKey, TValue, KeyValuePair<TKey, TValue>> mutator) 
{ 
    var removals = new List<TKey>(); 
    var additions = new List<KeyValuePair<TKey, TValue>>(); 

    foreach (var pair in dict) 
    { 
     var newPair = mutator(pair.Key, pair.Value); 
     if ((newPair.Key != pair.Key) || (newPair.Value != pair.Value)) 
     { 
      removals.Add(pair.Key); 
      additions.Add(newPair); 
     } 
    } 

    foreach (var removal in removals) 
     dict.Remove(removal); 

    foreach (var addition in additions) 
     dict.Add(addition.Key, addition.Value); 
} 

Notez que nous devons faire les mises à jour en dehors de la boucle, donc nous ne sommes pas en train de modifier le dictionnaire que nous énumérons il. En outre, cela détecte les conflits provoqués en faisant deux mêmes clés - il va jeter (en raison de l'utilisation de Add).

Exemple - faire toutes les touches minuscules et couper toutes les valeurs, avec un Dictionary<string, string>:

myDict.MutateEach(key => key.ToLower(), value => value.Trim()); 

Si les touches ne sont pas uniques en fait minuscule, cela jeter.