Pregunta

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

¿Fue útil?

Solución

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

Otros consejos

Si está intentando usar un diccionario genérico en C # como si fuera a usar 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 le interesan los valores:

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

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

En algunos casos, puede necesitar un contador que puede proporcionar 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 claves o los valores ...

Del MSDN Dictionary(TKey, TValue) Descripción de 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);
}

Generalmente, 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, también del gusto.

Por otro lado, hay muchas formas de iterar sobre un Diccionario en C # y no hay la 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 específico

Generalmente, los principiantes se sorprenden del 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)
}

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 <=>, más legible que <=>)
  • 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 del mundo real que puede hacer con estos ejemplos. Si no necesita un pedido específico, simplemente manténgase en & Quot; la forma más directa & Quot; (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 puede probar esto en grandes diccionarios para procesamiento multiproceso.

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

Hay muchas opciones. Mi favorito personal es 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 puede usar las Colecciones de claves y valores

Aprecio que esta pregunta ya haya recibido muchas respuestas, pero quería investigar un poco.

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 el mismo número de elementos) tomó 0.0365073 segundos, ¡2.4 veces más! 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, así 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";
}

Esta carga las claves y las repite en su lugar (también intenté tirar de 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 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, realicé mi iteración diez veces para ver si hay algún beneficio al usar las teclas aquí (en este punto tenía curiosidad):

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

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

Aquí la ejecución foreach normal tardó 0.2820564 segundos (aproximadamente diez veces más de lo que tomó una sola 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 usara 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 marque la diferencia sobre 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.
  • Si elige iterar sobre un diccionario, no intente ser demasiado inteligente, aunque más lento podría hacer mucho peor que usar el método foreach estándar.

C # 7.0 presentó Deconstructores y si está utilizando la aplicación .NET Core 2.0+ , la estructura KeyValuePair<> ya incluye un Deconstruct() para usted. Entonces puedes hacer:

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

 ingrese la descripción de la imagen aquí

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.

Con .NET Framework 4.7 uno puede usar descomposición

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

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

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

Forma más simple para iterar un diccionario:

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

Utilizando 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 use esta sintaxis simple

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


O este, 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 un tuple fuertemente tipado, permitiéndole usar esta nueva y cómoda sintaxis.

Convierte -solo- las entradas de diccionario requeridas a tuples, por lo que NO convierte todo el diccionario a Key, por lo que no hay problemas de rendimiento relacionados con eso.

Hay un costo menor que llama al método de extensión para crear un Value en comparación con el uso del <=> directamente, lo cual NO debería ser un problema si está asignando las propiedades del <=> <=> y <=> a nuevas variables de bucle de todos modos.

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

Mira esto: Blog de MSDN - Nuevas funciones en C # 7

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

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

Reportado por esta publicación que dice que es el método más rápido: http://alexpinsker.blogspot.hk/2010 /02/c-fastest-way-to-iterate-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 hacer funcionar correctamente en una clase que heredó 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
}

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 deconstruya:

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

Si dice, desea iterar sobre la colección de valores por defecto, creo que puede implementar IEnumerable < > ;, donde T es el tipo de objeto de valores en el diccionario, y quot; esto " es un diccionario

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
var dictionary = new Dictionary<string, int>
{
    { "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, 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 bien esto agrega una llamada adicional de '.ToList ()', podría haber una ligera mejora en el rendimiento (como se señala aquí foreach vs someList.Foreach () {} ), espacialmente cuando se trabaja con grandes diccionarios 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 quieres " lee " Claves y 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<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));

Sé que esta es una pregunta muy antigua, pero creé algunos métodos de extensión que podrían ser útiles:

    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 esta manera puedo escribir código como este:

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

Diccionario < TKey, & # 8194; TValue & Gt; es una clase de colección genérica en c # y almacena los datos en el formato del valor de la 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 se trata como KeyValuePair < TKey, & # 8194; TValue & Gt; estructura que representa una clave y su valor. y, por lo tanto, deberíamos tomar el tipo de elemento KeyValuePair < TKey, & # 8194; TValue & Gt; 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);
}

además de las publicaciones de mayor ranking 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
}

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 un genérico    definición 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 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 Add.

Para verificar si un diccionario tiene una determinada 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 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 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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top