How to iterate through Dictionary and change values?

Dictionary<string,double> myDict = new Dictionary();
//...
foreach (KeyValuePair<string,double> kvp in myDict)
{
kvp.Value = Math.Round(kvp.Value, 3);
}

I get an error: "Property or indexer 'System.Collections.Generic.KeyValuePair.Value' cannot be assigned to -- it is read only."
How can I iterate through myDict and change values?

83170 次浏览

迭代时不应该更改字典,否则会出现异常。

因此,首先将键值对复制到一个临时列表,然后迭代这个临时列表,然后更改字典:

Dictionary<string, double> myDict = new Dictionary<string, double>();


// a few values to play with
myDict["a"] = 2.200001;
myDict["b"] = 77777.3333;
myDict["c"] = 2.3459999999;


// prepare the temp list
List<KeyValuePair<string, double>> list = new List<KeyValuePair<string, double>>(myDict);


// iterate through the list and then change the dictionary object
foreach (KeyValuePair<string, double> kvp in list)
{
myDict[kvp.Key] = Math.Round(kvp.Value, 3);
}




// print the output
foreach (var pair in myDict)
{
Console.WriteLine(pair.Key + " = " + pair.Value);
}


// uncomment if needed
// Console.ReadLine();

输出(在我的机器上) :

A = 2.2
B = 77777.333
C = 2.346

注意 : 在性能方面,这个解决方案比当前提交的解决方案要好一些,因为值已经与键一起分配,而且不需要从 dictionary 对象中再次获取它。

循环通过字典中的键,而不是 KeyValuePears。

Dictionary<string, double> myDict = new Dictionary<string, double>();
//...
foreach (string key in myDict.Keys)
{
myDict[key] = Math.Round(myDict[key], 3);
}

根据 MSDN:

Foreach 语句是一个包装器 在枚举数周围,这允许 只读收藏品,不读 给它写信。

用这个:

var dictionary = new Dictionary<string, double>();
// TODO Populate your dictionary here
var keys = new List<string>(dictionary.Keys);
foreach (string key in keys)
{
dictionary[key] = Math.Round(dictionary[key], 3);
}

虽然直接遍历字典是不可能的,因为您得到了一个异常(就像 Ron 已经说过的) ,但是您不需要使用临时列表来解决这个问题。

相反,不要使用 foreach,而是使用 for循环来遍历字典并通过索引访问更改值:

Dictionary<string, double> myDict = new Dictionary<string,double>();
//...
for(int i = 0; i < myDict.Count; i++) {
myDict[myDict.ElementAt(i).Key] = Math.Round(myDict.ElementAt(i).Value, 3);
}

一种解决方案是事先将键放入一个列表(或另一个集合)中,并在更改字典时迭代它们:

Dictionary<string, double> dictionary = new Dictionary<string, double>();


// Populate it
List<string> keys = new List<string>(dictionary.Keys);


foreach (string key in keys)
{
dictionary[key] = Math.Round(dictionary[key], 3);
}

对于懒惰的程序员:

Dictionary<string, double> dictionary = new Dictionary<string, double>();
foreach (var key in dictionary.Keys.ToList())
{
dictionary[key] = Math.Round(dictionary[key], 3);
}

我注意到在 Dictionary 上迭代修改的最快方法是:

//Just a dumb class
class Test<T>
{
public T value;


public Test() { }
public Test(T v) { value = v; }
}


Dictionary<int, Test<object>> dic = new Dictionary<int, Test<object>>();
//Init dictionary
foreach (KeyValuePair<int, Test> pair in dic)
{
pair.Value.value = TheObject;//Modify
}

VS

List<int> keys = new List<int>(dic.Keys); //This is fast operation
foreach (int key in keys)
{
dic[key] = TheObject;
}

第一个测试需要2.2秒,第二个测试需要4.5秒(测试字典大小为1000,重复10k 次,将字典大小改为10并不改变比率)。另外,获取 Key 列表也没有什么大不了的,dictionary [ Key ] value get 只是在迭代中构建的慢速 VS。另外,如果你想要更快的速度使用硬编码类型哑(“测试”)类,我得到了它大约1.85 s (硬编码为“对象”)。

编辑:

安娜以前也发布过同样的解决方案: https://stackoverflow.com/a/6515474/766304

过了一段时间,但也许有人对它感兴趣:

yourDict = yourDict.ToDictionary(kv => kv.Key, kv => Math.Round(kv.Value, 3))