C# 在foreach循环中编辑字典值
我正试图从字典中建立一个饼图。在显示饼图之前,我想整理一下数据。我将删除任何少于5%的饼片,并将它们放在“其他”饼片中。然而,我得到一个C# 在foreach循环中编辑字典值,c#,.net,.net-2.0,C#,.net,.net 2.0,我正试图从字典中建立一个饼图。在显示饼图之前,我想整理一下数据。我将删除任何少于5%的饼片,并将它们放在“其他”饼片中。然而,我得到一个集合被修改;枚举操作在运行时可能不会执行异常 我理解为什么在迭代字典时不能从字典中添加或删除条目。但是,我不明白为什么不能在foreach循环中简单地更改现有键的值 任何关于:修复我的代码的建议,将不胜感激 Dictionary<string, int> colStates = new Dictionary<string,int>();
集合被修改;枚举操作在运行时可能不会执行
异常
我理解为什么在迭代字典时不能从字典中添加或删除条目。但是,我不明白为什么不能在foreach循环中简单地更改现有键的值
任何关于:修复我的代码的建议,将不胜感激
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);
Dictionary colStates=newdictionary();
// ...
//一些用于填充colStates字典的代码
// ...
int OtherCount=0;
foreach(colStates.Keys中的字符串键)
{
双百分比=colStates[键]/TotalCount;
如果(百分比<0.05)
{
OtherCount+=colStates[key];
colStates[key]=0;
}
}
添加(“其他”,其他计数);
在字典中设置值将更新其内部“版本号”-这将使迭代器以及与键或值集合关联的任何迭代器无效
我明白你的意思,但同时,如果values集合可以在迭代过程中更改,那就太奇怪了——为了简单起见,只有一个版本号
解决这类问题的常规方法是,预先复制密钥集合并在副本上迭代,或者在原始集合上迭代,但保留一个更改集合,在完成迭代后应用这些更改
例如:
首先复制密钥
List<string> keys = new List<string>(colStates.Keys);
foreach(string key in keys)
{
double percent = colStates[key] / TotalCount;
if (percent < 0.05)
{
OtherCount += colStates[key];
colStates[key] = 0;
}
}
List key=新列表(colStates.key);
foreach(字符串键入键)
{
双百分比=colStates[键]/TotalCount;
如果(百分比<0.05)
{
OtherCount+=colStates[key];
colStates[key]=0;
}
}
或者
创建修改列表
List<string> keysToNuke = new List<string>();
foreach(string key in colStates.Keys)
{
double percent = colStates[key] / TotalCount;
if (percent < 0.05)
{
OtherCount += colStates[key];
keysToNuke.Add(key);
}
}
foreach (string key in keysToNuke)
{
colStates[key] = 0;
}
List keystunke=new List();
foreach(colStates.Keys中的字符串键)
{
双百分比=colStates[键]/TotalCount;
如果(百分比<0.05)
{
OtherCount+=colStates[key];
keystunke.Add(key);
}
}
foreach(keystnuke中的字符串键)
{
colStates[key]=0;
}
您需要从旧词典创建新词典,而不是就地修改。类似的(也可以迭代KeyValuePair,而不是使用键查找:
int otherCount = 0;
int totalCounts = colStates.Values.Sum();
var newDict = new Dictionary<string,int>();
foreach (var kv in colStates) {
if (kv.Value/(double)totalCounts < 0.05) {
otherCount += kv.Value;
} else {
newDict.Add(kv.Key, kv.Value);
}
}
if (otherCount > 0) {
newDict.Add("Other", otherCount);
}
colStates = newDict;
int-otherCount=0;
int totalCounts=colStates.Values.Sum();
var newDict=新字典();
foreach(colStates中的var kv){
如果(千伏值/(双)总计数<0.05){
其他计数+=千伏值;
}否则{
新增(千伏键,千伏值);
}
}
如果(其他计数>0){
添加(“其他”,其他计数);
}
colStates=newDict;
免责声明:我不太喜欢C#
您正在尝试修改存储在哈希表中的DictionaryEntry对象。哈希表仅存储一个对象—DictionaryEntry的实例。更改键或值足以更改哈希表并导致枚举数无效
您可以在循环之外执行此操作:
if(hashtable.Contains(key))
{
hashtable[key] = value;
}
首先创建一个列表,列出您希望更改的值的所有键,然后遍历该列表。您不能修改集合,甚至不能修改值。您可以保存这些情况,稍后删除它们。结果如下:
Dictionary<string, int> colStates = new Dictionary<string, int>();
// ...
// Some code to populate colStates dictionary
// ...
int OtherCount = 0;
List<string> notRelevantKeys = new List<string>();
foreach (string key in colStates.Keys)
{
double Percent = colStates[key] / colStates.Count;
if (Percent < 0.05)
{
OtherCount += colStates[key];
notRelevantKeys.Add(key);
}
}
foreach (string key in notRelevantKeys)
{
colStates[key] = 0;
}
colStates.Add("Other", OtherCount);
Dictionary colStates=newdictionary();
// ...
//一些用于填充colStates字典的代码
// ...
int OtherCount=0;
List notRelevantKeys=新列表();
foreach(colStates.Keys中的字符串键)
{
双百分比=colStates[键]/colStates.Count;
如果(百分比<0.05)
{
OtherCount+=colStates[key];
不相关键。添加(键);
}
}
foreach(非相关键中的字符串键)
{
colStates[key]=0;
}
添加(“其他”,其他计数);
您正在修改此行中的集合:
colStates[key]=0
这样做,本质上就是在该点上删除并重新插入某些内容(就IEnumerable而言)
如果编辑要存储的值的一个成员,这是可以的,但是您正在编辑值本身,IEnumberable不喜欢这样
我使用的解决方案是消除foreach循环,只使用for循环。
简单的for循环不会检查您知道不会影响集合的更改
以下是您如何做到这一点:
List<string> keys = new List<string>(colStates.Keys);
for(int i = 0; i < keys.Count; i++)
{
string key = keys[i];
double Percent = colStates[key] / TotalCount;
if (Percent < 0.05)
{
OtherCount += colStates[key];
colStates[key] = 0;
}
}
List key=新列表(colStates.key);
对于(int i=0;i
您不能直接在ForEach中修改键或值,但可以修改其成员。例如,这应该可以:
public class State {
public int Value;
}
...
Dictionary<string, State> colStates = new Dictionary<string,State>();
int OtherCount = 0;
foreach(string key in colStates.Keys)
{
double Percent = colStates[key].Value / TotalCount;
if (Percent < 0.05)
{
OtherCount += colStates[key].Value;
colStates[key].Value = 0;
}
}
colStates.Add("Other", new State { Value = OtherCount } );
公共类状态{
公共价值观;
}
...
Dictionary colStates=新字典();
int OtherCount=0;
foreach(colStates.Keys中的字符串键)
{
双百分比=colStates[key]。值/TotalCount;
如果(百分比<0.05)
{
OtherCount+=colStates[key]。值;
colStates[key].Value=0;
}
}
添加(“其他”,新状态{Value=OtherCount});
对字典执行一些linq查询,然后将图形绑定到这些查询的结果,怎么样
var under = colStates.Where(c => (decimal)c.Value / (decimal)totalCount < .05M);
var over = colStates.Where(c => (decimal)c.Value / (decimal)totalCount >= .05M);
var newColStates = over.Union(new Dictionary<string, int>() { { "Other", under.Sum(c => c.Value) } });
foreach (var item in newColStates)
{
Console.WriteLine("{0}:{1}", item.Key, item.Value);
}
var=colStates.其中(c=>(十进制)c.Value/(十进制)totalCount<.05M);
var over=colStates,其中(c=>(十进制)c.Value/(十进制)totalCount>=.05M);
var newColStates=over.Union(new Dictionary(){{“Other”,在.Sum(c=>c.Value)}下);
foreach(NewColState中的var项目)
{
WriteLine(“{0}:{1}”,item.Key,item.Value);
}
如果你觉得有创意,你可以这样做。在字典中向后循环以进行更改
Dictionary<string, int> collection = new Dictionary<string, int>();
collection.Add("value1", 9);
collection.Add("value2", 7);
collection.Add("value3", 5);
collection.Add("value4", 3);
collection.Add("value5", 1);
for (int i = collection.Keys.Count; i-- > 0; ) {
if (collection.Values.ElementAt(i) < 5) {
collection.Remove(collection.Keys.ElementAt(i)); ;
}
}
Dictionary collection=newdictionary();
收款。添加(“价值1”,9);
上校
using System.Linq;
foreach(string key in colStates.Keys.ToList())
{
double Percent = colStates[key] / TotalCount;
if (Percent < 0.05)
{
OtherCount += colStates[key];
colStates[key] = 0;
}
}
new List<string>(myDict.Values).ForEach(str =>
{
//Use str in any other way you need here.
Console.WriteLine(str);
});
using System.Collections.Concurrent;
var colStates = new ConcurrentDictionary<string,int>();
colStates["foo"] = 1;
colStates["bar"] = 2;
colStates["baz"] = 3;
int OtherCount = 0;
int TotalCount = 100;
foreach(string key in colStates.Keys)
{
double Percent = (double)colStates[key] / TotalCount;
if (Percent < 0.05)
{
OtherCount += colStates[key];
colStates[key] = 0;
}
}
colStates.TryAdd("Other", OtherCount);
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class ConcurrentVsRegularDictionary
{
private readonly Random _rand;
private const int Count = 1_000;
public ConcurrentVsRegularDictionary()
{
_rand = new Random();
}
[Benchmark]
public void ConcurrentDictionary()
{
var dict = new ConcurrentDictionary<int, int>();
Populate(dict);
foreach (var key in dict.Keys)
{
dict[key] = _rand.Next();
}
}
[Benchmark]
public void Dictionary()
{
var dict = new Dictionary<int, int>();
Populate(dict);
foreach (var key in dict.Keys.ToArray())
{
dict[key] = _rand.Next();
}
}
private void Populate(IDictionary<int, int> dictionary)
{
for (int i = 0; i < Count; i++)
{
dictionary[i] = 0;
}
}
}
public class Program
{
public static void Main(string[] args)
{
BenchmarkRunner.Run<ConcurrentVsRegularDictionary>();
}
}
Method | Mean | Error | StdDev |
--------------------- |----------:|----------:|----------:|
ConcurrentDictionary | 182.24 us | 3.1507 us | 2.7930 us |
Dictionary | 47.01 us | 0.4824 us | 0.4512 us |
for (int i = 0; i < dictionary.Count; i++)
{
dictionary[dictionary.Keys.ElementAt(i)] = 0;
}
int iterations = 10;
int dictionarySize = 10000;
Stopwatch sw = new Stopwatch();
Console.WriteLine("Creating dictionary...");
Dictionary<string, int> dictionary = new Dictionary<string, int>(dictionarySize);
for (int i = 0; i < dictionarySize; i++)
{
dictionary.Add(i.ToString(), i);
}
Console.WriteLine("Done");
Console.WriteLine("Starting tests...");
// for loop test
sw.Restart();
for (int i = 0; i < iterations; i++)
{
for (int j = 0; j < dictionary.Count; j++)
{
dictionary[dictionary.Keys.ElementAt(j)] = 3;
}
}
sw.Stop();
Console.WriteLine($"for loop Test: {sw.ElapsedMilliseconds} ms");
// foreach loop test
sw.Restart();
for (int i = 0; i < iterations; i++)
{
foreach (string key in dictionary.Keys.ToList())
{
dictionary[key] = 3;
}
}
sw.Stop();
Console.WriteLine($"foreach loop Test: {sw.ElapsedMilliseconds} ms");
Console.WriteLine("Done");
foreach (var pair in dict)
dict[pair.Key] = pair.Value + 1;