recorrer new ejemplos c# dictionary loops

new - return dictionary c#



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

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


A partir de C # 7, puede 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<TKey, TVal> que lo KeyValuePair<TKey, TVal> :

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

Iterar sobre cualquier Dictionary<TKey, TVal> de la siguiente manera

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



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 en comparación con iterar sobre algo 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 la misma cantidad de elementos) tomó 0.0365073 segundos, ¡lo cual es 2.4 veces más largo! Aunque he visto diferencias mucho mayores. Para comparación, una lista estaba en algún punto intermedio entre 0.00215043 segundos.

Sin embargo, eso es como comparar manzanas y naranjas. Mi punto es que la iteración sobre los diccionarios es lenta.

Los diccionarios están optimizados para búsquedas, por lo que con eso en mente, 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<string, string> dictionary) { string value; int count = 0; foreach (var kvp in dictionary) { value = kvp.Value; count++; } return "Normal"; }

Este carga las claves y las itera sobre ellas (también intenté jalar las claves en una cadena [], pero la diferencia fue insignificante.

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

Con este ejemplo, la prueba normal de foreach tomó 0.0310062 y la versión de las llaves 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 al usar las teclas aquí (en este punto, solo tenía curiosidad):

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

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

En este caso, la ejecución normal de foreach tomó 0.2820564 segundos (aproximadamente diez veces más de lo que tomó una iteración, como era de esperar). La iteración sobre las teclas tomó 2.2249449 segundos.

Editado para agregar: Al leer algunas de las otras respuestas, me pregunté qué pasaría si utilizara Diccionario en lugar de Diccionario. En este ejemplo, la matriz tomó 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 en cuanto a la lentitud del 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 en él.
  • Si elige iterar sobre un diccionario, no intente ser demasiado inteligente, aunque más lento podría hacerlo mucho peor que usar el método estándar para cada método.

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

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


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

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

Para hacer que este código funcione en versiones de C # más bajas, agregue el System.ValueTuple NuGet package y escriba en algún lugar

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


Depende de si buscas las claves 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<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); }


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

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


En general, pedir "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, 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, del gusto.

Manera más sencilla

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 específico

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

LINQ proporciona una sintaxis 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) }

Una vez más, es posible que sólo necesite el valor. LINQ también proporciona una solución concisa para:

  • iterar directamente en el valor (permite llamarlo item , más legible que kvp.Value )
  • pero ordenados por las llaves

Aquí está:

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

Hay muchos más casos de uso del mundo real que puede hacer a partir de estos ejemplos. Si no necesita una orden específica, simplemente siga la "manera más directa" (ver arriba).


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 que heredó de DictionaryBase.


Escribí una extensión para recorrer un diccionario.

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

Entonces puedes llamar

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


Hay un montón de opciones. Mi favorito personal es por KeyValuePair

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

También puedes utilizar las colecciones de claves y valores.


La forma estándar de iterar sobre un Diccionario, según la documentación oficial en MSDN es:

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


La forma más simple de iterar un diccionario:

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


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<string, long> phonebook = new Dictionary<string, long>(); 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 de 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 solo valor al diccionario, ya sea usando el operador de corchetes o usando el método Agregar.

Para verificar si un diccionario tiene cierta clave, podemos usar el método 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"]); }

Para eliminar un elemento de un diccionario, podemos utilizar 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 utilizando su valor, el proceso es lento e ineficiente, a diferencia de la función Eliminar del diccionario.

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


Por ejemplo, si desea iterar sobre la colección de valores de forma predeterminada, creo que puede implementar IEnumerable <>, donde T es el tipo de objeto de valores en el diccionario, y "este" es un Diccionario.

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


Si está intentando usar un Diccionario genérico en C #, como si usara una matriz asociativa en otro idioma:

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

O, si solo necesita iterar sobre 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í)


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

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

Si esto agrega una llamada adicional de ''.ToList ()'', puede haber una leve mejora en el rendimiento (como se indica aquí para cada vs vs. Lista.Para cada () {} ), especialmente cuando se trabaja con grandes diccionarios y se ejecuta en paralelo no Opción / no tendrá ningún efecto en absoluto.

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 causando problemas en el tiempo de ejecución.

Cuando solo quiere "leer" Claves y valores, también puede usar IEnumerable.Select ().

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


También puede probar esto en diccionarios grandes para procesamiento multiproceso.

dictionary .AsParallel() .ForAll(pair => { // Process pair.Key and pair.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<TKey, TValue>( this IDictionary<TKey, TValue> dict) { foreach (KeyValuePair<TKey, TValue> kvp in dict) yield return (kvp.Key, kvp.Value); } }


Y usa esta sintaxis simple

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


O éste, si lo prefieres.

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


En lugar de lo tradicional.

foreach (KeyValuePair<string, object> 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<TKey, TValue> en una tuple fuertemente IDictionary<TKey, TValue> , lo que le permite utilizar esta nueva sintaxis cómoda.

Convierte, simplemente, las entradas requeridas del diccionario 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 solo costo menor que llama al método de extensión para crear una tuple en comparación con el uso de KeyValuePair directamente, lo que NO debería ser un problema si está asignando la Key y el Value propiedades de KeyValuePair a nuevas variables de bucle.

En la práctica, esta nueva sintaxis se adapta muy bien para la mayoría de los casos, excepto en los escenarios de rendimiento ultraalto de bajo nivel, donde aún tiene la opción de simplemente no usarla en ese lugar específico.

Mira esto: MSDN Blog - Nuevas características en C # 7


Usted sugirió a continuación para iterar

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

Para su información, foreach no funciona si el valor es de tipo objeto.


Yo 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?


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

foreach(KeyValuePair<string, string> 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<string, string>(x);//fill dictionary with x foreach(var kvp in myDictionary)//iterate over dictionary { // do something with kvp.Value or kvp.Key }


Dictionary <TKey, TValue> Es una clase de colección genérica en c # y almacena los datos en el formato del valor 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 tratado como KeyValuePair <TKey, TValue> estructura que representa una clave y su valor. y por lo tanto deberíamos tomar el tipo de elemento KeyValuePair <TKey, TValue> durante la iteración del elemento. A continuación se muestra el ejemplo.

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


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


var dictionary = new Dictionary<string, int> { { "Key", 12 } }; var aggregateObjectCollection = dictionary.Select( entry => new AggregateObject(entry.Key, entry.Value));