Как перебирать словарь и изменять значения?
Dictionary<string,double> myDict = new Dictionary();
//...
foreach (KeyValuePair<string,double> kvp in myDict)
{
kvp.Value = Math.Round(kvp.Value, 3);
}Я получаю сообщение об ошибке:
"Система свойств или индексаторов.Коллекции.Родовой.KeyValuePair.Значение ' не может быть присвоено -- оно доступно только для чтения."
Как я могу перебирать myDict и меняем ценности?
8 ответов:
по данным 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); }
для ленивых программистов:
Dictionary<string, double> dictionary = new Dictionary<string, double>(); foreach (var key in dictionary.Keys.ToList()) { dictionary[key] = Math.Round(dictionary[key], 3); }
вы не должны изменять словарь во время его итерации, иначе вы получите исключение.
Итак, сначала скопируйте пары ключ-значение в список temp, а затем повторите этот список temp, а затем измените свой словарь:
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Примечание: С точки зрения производительности, это решение немного лучше, чем в настоящее время опубликовано решения, так как значение уже назначено ключом, и нет необходимости снова извлекать его из объекта словаря.
Я заметил, что самый быстрый способ (на данный момент) перебирать словарь с помощью modify:
//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 не изменило соотношения). Также не было большой проблемы с получением списка ключей, dictionary [key] value get-это просто медленная VS встроенная итерация. Также, если вы хотите еще больше скорости, используйте жесткий кодированный тип, чтобы немой ("Тест") класс, с которым я получил его около 1.85 s (с жестко закодированным "объектом").
EDIT:
Анна опубликовала такое же решение раньше:https://stackoverflow.com/a/6515474/766304
одним из решений было бы поместить ключи в список (или другую коллекцию) заранее и перебирать их при изменении словаря:
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); }
прошло некоторое время, но, может быть, кто-то в этом заинтересован:
yourDict = yourDict.ToDictionary(kv => kv.Key, kv => Math.Round(kv.Value, 3))
хотя итерация по словарю напрямую невозможна, потому что вы получаете исключение (как уже сказал Рон), вам не нужно использовать временный список для решения проблемы.
вместо этого используйте не
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); }
цикл через ключи в словаре, а не KeyValuePairs.
Dictionary<string, double> myDict = new Dictionary<string, double>(); //... foreach (string key in myDict.Keys) { myDict[key] = Math.Round(myDict[key], 3); }
Comments