开发者

How to iterate through Dictionary and change values?

开发者 https://www.devze.com 2022-12-19 22:54 出处:网络
Dictionary<string,double> myDict = new Dictionary(); //... foreach (KeyValuePair<string,double> kvp in myDict)
Dictionary<string,double> myDict = new Dictionary();
//...
foreach (KeyValuePair<string,double> kvp in myDict)
 {
     kvp.Value = Math.Round(kvp.Value, 3);
}

I get an error: "Prop开发者_StackOverflow中文版erty or indexer 'System.Collections.Generic.KeyValuePair.Value' cannot be assigned to -- it is read only."

How can I iterate through myDict and change values?


According to MSDN:

The foreach statement is a wrapper around the enumerator, which allows only reading from the collection, not writing to it.

Use this:

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


For the lazy programmers:

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


You shouldn't change the dictionary while iterating it, otherwise you get an exception.

So first copy the key-value pairs to a temp list and then iterate through this temp list and then change your dictionary:

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

output (on my machine):

a = 2.2
b = 77777.333
c = 2.346

Note: in terms of performance, this solution is a bit better than currently posted solutions, since the value is already assigned with the key, and there's no need to fetch it again from the dictionary object.


passed some time, but maybe someone is interested in it:

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


I noticed that fastest way (at this moment) iterate over Dictionary with modify is:

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

First one takes about 2.2s and second one 4.5s (tested dictionary size of 1000 and repeated 10k time, changing dictionary size to 10 didn't change the ratios). Also there wasn't a big deal with getting the Key list, dictionary[key] value get is just slow VS built in iteration. Also if you want even more speed use hard coded type to dumb ("Test") class, with that I got it about 1.85s (with hard coded to "object").

EDIT:

Anna has posted the same solution before: https://stackoverflow.com/a/6515474/766304


One solution would be to put the keys in a list (or another collection) beforehand and iterate through them while changing the dictionary:

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


While iterating over the dictionary directly is not possible because you get an exception (like Ron already said), you don't need to use a temp list to solve the problem.

Instead use not the foreach, but a for loop to iterate through the dictionary and change the values with indexed access:

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


Loop through the keys in the dictionary, not the KeyValuePairs.

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

精彩评论

暂无评论...
验证码 换一张
取 消