c# - value - idictionary foreach




Qual é a melhor maneira de iterar em um dicionário? (17)

Às vezes, se você precisar apenas dos valores a serem enumerados, use a coleção de valores do dicionário:

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

Relatado por este post, que afirma ser o método mais rápido: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html

Eu vi algumas maneiras diferentes de iterar em um dicionário em C #. Existe um caminho padrão?


A maneira padrão de iterar sobre um dicionário, de acordo com a documentação oficial no MSDN é:

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

Com o .NET Framework 4.7 pode-se usar a decomposição

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

Para fazer este código funcionar em versões C # mais baixas, adicione o System.ValueTuple NuGet package e escreva em algum 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 se você está atrás das chaves ou dos valores ...

Do Dictionary(TKey, TValue) MSDN Dictionary(TKey, TValue) Descrição da 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);
}

Em alguns casos, você pode precisar de um contador que pode ser fornecido pela implementação de loop. Para isso, o LINQ fornece o ElementAt que permite o seguinte:

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

Eu aprecio essa pergunta que já teve muitas respostas, mas eu queria fazer uma pequena pesquisa.

Iterar sobre um dicionário pode ser bastante lento quando comparado com iterar algo como um array. Em meus testes, uma iteração em uma matriz levou 0,015003 segundos, enquanto uma iteração sobre um dicionário (com o mesmo número de elementos) levou 0,0365073 segundos, o que representa 2,4 vezes mais tempo! Embora eu tenha visto diferenças muito maiores. Para comparação, uma lista estava em algum lugar entre 0,00215043 segundos.

No entanto, isso é como comparar maçãs e laranjas. Meu ponto é que iterar sobre dicionários é lento.

Os dicionários são otimizados para pesquisas, então, com isso em mente, criei dois métodos. Um simplesmente faz um foreach, o outro itera as teclas e então olha para cima.

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 carrega as teclas e repete sobre elas (eu também tentei puxar as chaves para uma string [], mas a diferença foi 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";
}

Com este exemplo, o teste normal foreach levou 0,0310062 e a versão das chaves levou 0,2205441. Carregar todas as chaves e iterar sobre todas as pesquisas é claramente muito mais lento!

Para um teste final, realizei minha iteração dez vezes para ver se há algum benefício em usar as chaves aqui (nesse ponto, fiquei curioso):

Aqui está o método RunTest, se isso ajudar você a visualizar o que está acontecendo.

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

Aqui, a corrida normal foreach demorou 0.2820564 segundos (cerca de dez vezes mais do que uma única iteração - como seria de se esperar). A iteração sobre as teclas levou 2.2249449 segundos.

Editado para adicionar: Ler algumas das outras respostas me fez questionar o que aconteceria se eu usasse o dicionário em vez do dicionário. Neste exemplo, a matriz levou 0,0120024 segundos, a lista 0,0185037 segundos e o dicionário 0,0465093 segundos. É razoável esperar que o tipo de dados faça diferença em quanto mais lento o dicionário.

Quais são minhas conclusões ?

  • Evite iterar sobre um dicionário se você puder, eles são substancialmente mais lentos do que iterar em um array com os mesmos dados nele.
  • Se você optar por iterar sobre um dicionário, não tente ser inteligente demais, embora seja mais lento do que usar o método foreach padrão.

Eu encontrei este método na documentação para a classe DictionaryBase no MSDN:

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

Este foi o único que consegui funcionar corretamente em uma classe herdada do DictionaryBase.


Eu escrevi uma extensão para percorrer um dicionário.

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

Então você pode ligar

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

Geralmente, pedir "o melhor caminho" sem um contexto específico é como perguntar qual é a melhor cor.

Por um lado, há muitas cores e não há melhor cor. Depende da necessidade e também do gosto também.

Por outro lado, há muitas maneiras de iterar sobre um dicionário em C # e não há melhor maneira. Depende da necessidade e também do gosto também.

Maneira mais direta

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

Se você precisar apenas do valor (permite chamá-lo de item , mais legível que kvp.Value ).

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

Se você precisar de uma ordem de classificação específica

Geralmente, os novatos ficam surpresos com a ordem de enumeração de um Dicionário.

O LINQ fornece uma sintaxe concisa que permite especificar a ordem (e muitas outras coisas), por exemplo:

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

Novamente, você pode precisar apenas do valor. O LINQ também fornece uma solução concisa para:

  • iterar diretamente no valor (permite chamá-lo de item , mais legível que kvp.Value )
  • mas ordenado pelas chaves

Aqui está:

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

Há muito mais casos de uso do mundo real que você pode fazer com esses exemplos. Se você não precisa de um pedido específico, basta seguir o "caminho mais simples" (veja acima)!


Há muitas opções. Meu favorito pessoal é da KeyValuePair

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

Você também pode usar as Coleções de Chaves e Valores


Se você está tentando usar um dicionário genérico em C # como você usaria uma matriz associativa em outro idioma:

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

Ou, se você só precisar iterar sobre a coleção de chaves, use

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

E por último, se você está interessado apenas nos valores:

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

(Observe que a palavra-chave var é um recurso C # 3.0 e superior opcional, você também pode usar o tipo exato de suas chaves / valores aqui)


Se você quiser iterar sobre a coleção de valores por padrão, acredito que você possa implementar IEnumerable <>, Onde T é o tipo do objeto de valores no dicionário e "this" é um Dictionary.

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

Você sugeriu abaixo 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;
}

FYI, foreach não funciona se o valor for do tipo objeto.


Você também pode tentar isso em grandes dicionários para processamento multithread.

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

além das postagens mais altas, onde há uma discussão entre usar

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

ou

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

mais completo é o seguinte, porque você pode ver o tipo de dicionário a partir da inicialização, kvp é 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> É uma classe de coleção genérica em c # e armazena os dados no formato do valor da chave. A chave deve ser única e não pode ser nula, enquanto o valor pode ser duplicado e nulo.Como cada item no dicionário é tratada como KeyValuePair <TKey, TValue> estrutura representando uma chave e seu valor. e, portanto, devemos usar o tipo de elemento KeyValuePair <TKey, TValue> durante a iteração do elemento. Abaixo está o exemplo.

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

var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));




loops