¿Cuál es la mejor manera de iterar sobre un diccionario?

He visto algunas maneras diferentes de iterar sobre un diccionario en C #. ¿Hay una forma estándar?

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

Si está tratando de usar un diccionario genérico en C # como si fuera una matriz asociativa en otro idioma:

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

O, si solo necesita repetir la colección de claves, use

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

Y, por último, si solo te interesan los valores:

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

(Tenga en cuenta que la palabra clave var es una característica opcional de C # 3.0 y superior, también puede usar el tipo exacto de sus claves / valores aquí)

En algunos casos, es posible que necesite un contador que puede ser proporcionado por la implementación for-loop. Para eso, LINQ proporciona ElementAt que permite lo siguiente:

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

Depende de si buscas las llaves o los valores …

Desde el Dictionary(TKey, TValue) MSDN Dictionary(TKey, TValue) Descripción de la clase:

 // When you use foreach to enumerate dictionary elements, // the elements are retrieved as KeyValuePair objects. Console.WriteLine(); foreach( KeyValuePair kvp in openWith ) { Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value); } // To get the values alone, use the Values property. Dictionary.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.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); } 

En general, preguntar por “la mejor manera” sin un contexto específico es como preguntar cuál es el mejor color.

Por un lado, hay muchos colores y no hay mejor color. Depende de la necesidad y, a menudo también del gusto.

Por otro lado, hay muchas maneras de iterar sobre un diccionario en C # y no hay una mejor manera. Depende de la necesidad y, a menudo también del gusto.

La forma más directa

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

Si solo necesita el valor (permite llamarlo item , más legible que kvp.Value ).

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

Si necesita un orden de clasificación específico

En general, los principiantes se sorprenden por el orden de enumeración de un diccionario.

LINQ proporciona una syntax concisa que permite especificar el orden (y muchas otras cosas), por ejemplo:

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

De nuevo, es posible que solo necesite el valor. LINQ también proporciona una solución concisa para:

  • iterar directamente sobre el valor (permite llamarlo item , más legible que kvp.Value )
  • pero ordenado por las teclas

Aquí está:

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

Hay muchos más casos de uso en el mundo real que puede hacer a partir de estos ejemplos. Si no necesita un pedido específico, simplemente manténgase en la “forma más directa” (ver arriba).

Diría que foreach es la forma estándar, aunque obviamente depende de lo que estés buscando

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

¿Es eso lo que estás buscando?

También puedes probar esto en diccionarios grandes para procesar multiproceso.

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

Hay muchas opciones. Mi favorito personal es por KeyValuePair

 Dictionary myDictionary = new Dictionary(); // Populate your dictionary here foreach (KeyValuePair kvp in myDictionary) { // Do some interesting things } 

También puede usar las Colecciones de claves y valores

Aprecio que esta pregunta ya haya tenido muchas respuestas, pero quería hacer un poco de investigación.

Iterar sobre un diccionario puede ser bastante lento cuando se compara con iterar sobre algo así como una matriz. En mis pruebas una iteración sobre una matriz tomó 0.015003 segundos, mientras que una iteración sobre un diccionario (con el mismo número de elementos) tomó 0.0365073 segundos, ¡es 2.4 veces más largo! Aunque he visto diferencias mucho mayores. Para comparar, una Lista estaba en algún punto intermedio en 0.00215043 segundos.

Sin embargo, eso es como comparar manzanas y naranjas. Mi punto es que iterar sobre los diccionarios es lento.

Los diccionarios están optimizados para búsquedas, por lo que he creado dos métodos. Uno simplemente hace un foreach, el otro itera las teclas y luego mira hacia arriba.

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

Éste carga las claves y las itera en su lugar (también intenté tirar las llaves en una cadena [] pero la diferencia fue insignificante.

 public static string Keys(Dictionary dictionary) { string value; int count = 0; foreach (var key in dictionary.Keys) { value = dictionary[key]; count++; } return "Keys"; } 

Con este ejemplo, la prueba foreach normal tomó 0.0310062 y la versión de claves tomó 0.2205441. ¡Cargar todas las claves e iterar sobre todas las búsquedas es claramente MUCHO más lento!

Para una prueba final, he realizado mi iteración diez veces para ver si hay algún beneficio con el uso de las teclas aquí (en este momento solo tenía curiosidad):

Aquí está el método RunTest si eso te ayuda a visualizar lo que está sucediendo.

 private static string RunTest(T dictionary, Func 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); } 

Aquí la ejecución foreach normal tomó 0.2820564 segundos (alrededor de diez veces más de lo que requería una única iteración, como era de esperar). La iteración sobre las teclas tomó 2.2249449 segundos.

Editado para agregar: Leer algunas de las otras respuestas me hizo preguntarme qué pasaría si usaba Dictionary en lugar de Dictionary. En este ejemplo, la matriz tardó 0.0120024 segundos, la lista 0.0185037 segundos y el diccionario 0.0465093 segundos. Es razonable esperar que el tipo de datos haga una diferencia sobre cuánto más lento es el diccionario.

¿Cuáles son mis conclusiones ?

  • Evite iterar sobre un diccionario si puede, son sustancialmente más lentos que iterar sobre una matriz con los mismos datos.
  • Si eliges iterar sobre un diccionario, no intentes ser demasiado inteligente, aunque más lento podrías hacer mucho peor que usar el método foreach estándar.

Usted sugirió a continuación para iterar

 Dictionary myDictionary = new Dictionary(); //Populate your dictionary here foreach (KeyValuePair kvp in myDictionary) { //Do some interesting things; } 

FYI, foreach no funciona si el valor es de tipo objeto.

Con .NET Framework 4.7 uno puede usar la descomposición

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

Para hacer que este código funcione en versiones de C # inferiores, agregue el System.ValueTuple NuGet package y escriba en alguna parte

 public static class MyExtensions { public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value) { key = tuple.Key; value = tuple.Value; } } 

Forma más simple de iterar un diccionario:

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

A veces, si solo necesita los valores que se enumerarán, use la colección de valores del diccionario:

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

Reportado por este post que afirma que es el método más rápido: http://alexpinsker.blogspot.hk/2010/02/c-fastas-viaje-a-iterar-over.html

Encontré este método en la documentación de la clase DictionaryBase en MSDN:

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

Este fue el único que pude obtener funcionando correctamente en una clase heredada de DictionaryBase.

Aprovecharé .NET 4.0+ y proporcionaré una respuesta actualizada a la originalmente aceptada:

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

La forma estándar de iterar sobre un diccionario, de acuerdo con la documentación oficial en MSDN es:

 foreach (DictionaryEntry entry in myDictionary) { //Read entry.Key and entry.Value here } 

Usando C # 7 , agregue este método de extensión a cualquier proyecto de su solución:

 public static class IDictionaryExtensions { public static IEnumerable<(TKey, TValue)> Tuples( this IDictionary dict) { foreach (KeyValuePair kvp in dict) yield return (kvp.Key, kvp.Value); } } 

Y usa esta syntax simple

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

O este, si prefieres

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

En lugar de lo tradicional

 foreach (KeyValuePair kvp in dict) { string id = kvp.Key; object value = kvp.Value; // your code using 'id' and 'value' } 

El método de extensión transforma el KeyValuePair de su IDictionary en una tuple fuertemente IDictionary , lo que le permite utilizar esta nueva y cómoda syntax.

Convierte -simultáneamente- las entradas de diccionario requeridas en tuples , por lo que NO convierte todo el diccionario en tuples , por lo que no hay problemas de rendimiento relacionados con eso.

Hay un único costo menor para llamar al método de extensión para crear una tuple en comparación con el uso del KeyValuePair directamente, lo cual NO debería ser un problema si está asignando las propiedades Key y Value KeyValuePair todas formas a las nuevas variables de bucle.

En la práctica, esta nueva syntax se adapta muy bien para la mayoría de los casos, a excepción de los escenarios de alto rendimiento de bajo nivel, donde todavía tiene la opción de simplemente no usarlo en ese punto específico.

Mira esto: MSDN Blog – Nuevas funciones en C # 7

Si, por ejemplo, desea iterar sobre la colección de valores de forma predeterminada, creo que puede implementar IEnumerable <>, donde T es el tipo del objeto de valores en el diccionario, y “esto” es un diccionario.

 public new IEnumerator GetEnumerator() { return this.Values.GetEnumerator(); } 

A partir de C # 7, puedes deconstruir objetos en variables. Creo que esta es la mejor manera de iterar sobre un diccionario.

Ejemplo:

Cree un método de extensión en KeyValuePair que lo deconstruye:

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

Itera sobre cualquier Dictionary de la siguiente manera

 // Dictionary can be of any types, just using 'int' and 'string' as examples. Dictionary dict = new Dictionary(); // Deconstructor gets called here. foreach (var (key, value) in dict) { Console.WriteLine($"{key} : {value}"); } 
 var dictionary = new Dictionary { { "Key", 12 } }; var aggregateObjectCollection = dictionary.Select( entry => new AggregateObject(entry.Key, entry.Value)); 

Solo quería agregar mi 2 centavo, ya que la mayoría de las respuestas se relacionan con foreach-loop. Por favor, mira el siguiente código:

 Dictionary myProductPrices = new Dictionary(); //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)); }); 

Si bien esto agrega una llamada adicional de ‘.ToList ()’, puede haber una ligera mejora en el rendimiento (como se señala aquí foreach vs someList.Foreach () {} ), especialmente cuando se trabaja con diccionarios grandes y se ejecuta en paralelo no hay opción / no tendrá ningún efecto.

Además, tenga en cuenta que no podrá asignar valores a la propiedad ‘Valor’ dentro de un bucle foreach. Por otro lado, también podrás manipular la ‘Clave’, posiblemente metiéndote en problemas en tiempo de ejecución.

Cuando solo quiere “leer” las claves y los valores, también puede usar IEnumerable.Select ().

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

Escribí una extensión para recorrer un diccionario.

 public static class DictionaryExtension { public static void ForEach(this Dictionary dictionary, Action action) { foreach(KeyValuePair keyValue in dictionary) { action(keyValue.Key, keyValue.Value); } } } 

Entonces puedes llamar

 myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y)); 

Dictionary Es una clase de colección genérica en c # y almacena los datos en el formato de valor de clave. La clave debe ser única y no puede ser nula, mientras que el valor puede ser duplicado y nulo. Como cada elemento del diccionario es tratada como estructura KeyValuePair que representa una clave y su valor. y por lo tanto, debemos tomar el elemento tipo KeyValuePair durante la iteración del elemento. A continuación está el ejemplo.

 Dictionary dict = new Dictionary(); dict.Add(1,"One"); dict.Add(2,"Two"); dict.Add(3,"Three"); foreach (KeyValuePair item in dict) { Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value); } 

además de los puestos de más alto rango donde hay una discusión entre el uso

 foreach(KeyValuePair 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 } 

el más completo es el siguiente porque puede ver el tipo de diccionario desde la inicialización, kvp es KeyValuePair

 var myDictionary = new Dictionary(x);//fill dictionary with x foreach(var kvp in myDictionary)//iterate over dictionary { // do something with kvp.Value or kvp.Key } 

Los diccionarios son listas especiales, mientras que cada valor en la lista tiene una clave que también es una variable. Un buen ejemplo de un diccionario es una guía telefónica.

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

Tenga en cuenta que al definir un diccionario, debemos proporcionar una definición genérica con dos tipos: el tipo de clave y el tipo del valor. En este caso, la clave es una cadena mientras que el valor es un número entero.

También hay dos formas de agregar un valor único al diccionario, ya sea usando el operador de corchetes o usando el método Agregar.

Para verificar si un diccionario tiene determinada clave, podemos usar el método ContainsKey:

 Dictionary phonebook = new Dictionary(); phonebook.Add("Alex", 415434543); phonebook["Jessica"] = 415984588; if (phonebook.ContainsKey("Alex")) { Console.WriteLine("Alex's number is " + phonebook["Alex"]); } 

Para eliminar un elemento de un diccionario, podemos usar el método Eliminar. Eliminar un elemento de un diccionario por su clave es rápido y muy eficiente. Al eliminar un elemento de una lista usando su valor, el proceso es lento e ineficiente, a diferencia de la función Eliminar diccionario.

 Dictionary phonebook = new Dictionary(); phonebook.Add("Alex", 415434543); phonebook["Jessica"] = 415984588; phonebook.Remove("Jessica"); Console.WriteLine(phonebook.Count);