Estou tentando criar um gráfico de pizza a partir de um dicionário. Antes de exibir o gráfico de pizza, quero arrumar os dados. Estou removendo as fatias de torta que seriam inferiores a 5% da torta e colocando-as em uma fatia de "Outros". No entanto, estou recebendo uma Collection was modified; enumeration operation may not execute
exceção em tempo de execução.
Entendo por que você não pode adicionar ou remover itens de um dicionário enquanto itera sobre eles. No entanto, não entendo por que você não pode simplesmente alterar um valor para uma chave existente no loop foreach.
Qualquer sugestão re: corrigir o meu código, seria apreciada.
Dictionary<string, int> colStates = new Dictionary<string,int>();
// ...
// Some code to populate colStates dictionary
// ...
int OtherCount = 0;
foreach(string key in colStates.Keys)
{
double Percent = colStates[key] / TotalCount;
if (Percent < 0.05)
{
OtherCount += colStates[key];
colStates[key] = 0;
}
}
colStates.Add("Other", OtherCount);
Ligue
ToList()
para oforeach
loop. Dessa forma, não precisamos de uma cópia de variável temporária. Depende do Linq, que está disponível desde .Net 3.5.fonte
foreach(var pair in colStates.ToList())
para evitar ter acesso à chave e o valor que evita a necessidade de pôr emcolStates[key]
..Você está modificando a coleção nesta linha:
Ao fazer isso, você está essencialmente excluindo e reinserindo algo nesse ponto (no que diz respeito ao IEnumerable de qualquer maneira.
Se você editar um membro do valor que está armazenando, tudo bem, mas você está editando o próprio valor e IEnumberable não gosta disso.
A solução que usei é eliminar o loop foreach e usar um loop for. Um loop for simples não verificará as alterações que você sabe que não afetarão a coleção.
Veja como você pode fazer isso:
fonte
colStates.Keys
no lugar dekeys
.Você não pode modificar as chaves nem os valores diretamente em um ForEach, mas pode modificar seus membros. Por exemplo, isso deve funcionar:
fonte
Que tal fazer algumas consultas linq no seu dicionário e vincular seu gráfico aos resultados deles? ...
fonte
Se você estiver se sentindo criativo, poderá fazer algo assim. Faça um retrocesso no dicionário para fazer suas alterações.
Certamente não é idêntico, mas você pode estar interessado de qualquer maneira ...
fonte
Você precisa criar um novo dicionário a partir do antigo, em vez de modificar no local. Algo parecido (também itere sobre KeyValuePair <,> em vez de usar uma pesquisa de chave:
fonte
Iniciando com o .NET 4.5 Você pode fazer isso com o ConcurrentDictionary :
Observe, no entanto, que seu desempenho é realmente muito pior que um simples
foreach dictionary.Kes.ToArray()
:Resultado:
fonte
Você não pode modificar a coleção, nem mesmo os valores. Você pode salvar esses casos e removê-los mais tarde. Terminaria assim:
fonte
Isenção de responsabilidade: eu não faço muito c #
Você está tentando modificar o objeto DictionaryEntry que é armazenado no HashTable. O Hashtable armazena apenas um objeto - sua instância do DictionaryEntry. Alterar a chave ou o valor é suficiente para alterar a HashTable e fazer com que o enumerador se torne inválido.
Você pode fazer isso fora do loop:
criando primeiro uma lista de todas as chaves dos valores que você deseja alterar e iterar por essa lista.
fonte
Você pode fazer uma cópia da lista e
dict.Values
, em seguida, usar aList.ForEach
função lambda para iteração (ou umforeach
loop, conforme sugerido anteriormente).fonte
Juntamente com as outras respostas, pensei em observar que, se você obtiver
sortedDictionary.Keys
ou, emsortedDictionary.Values
seguidaforeach
, passar por cima delas , você também será ordenado. Isso ocorre porque esses métodos retornamSystem.Collections.Generic.SortedDictionary<TKey,TValue>.KeyCollection
ouSortedDictionary<TKey,TValue>.ValueCollection
objetos, que mantêm o tipo do dicionário original.fonte
Esta resposta é para comparar duas soluções, não uma solução sugerida.
Em vez de criar outra lista conforme as outras respostas sugeridas, você pode usar um
for
loop usando o dicionárioCount
para a condição de parada de loop eKeys.ElementAt(i)
obter a chave.No começo, pensei que isso seria mais eficiente, porque não precisamos criar uma lista de chaves. Depois de executar um teste, descobri que a
for
solução de loop é muito menos eficiente. O motivo é porqueElementAt
O (n) está nodictionary.Keys
propriedade, ele pesquisa desde o início da coleção até chegar ao enésimo item.Teste:
Resultados:
fonte