Как перебирать словарь и изменять значения?



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


Я получаю сообщение об ошибке:
"Система свойств или индексаторов.Коллекции.Родовой.KeyValuePair.Значение ' не может быть присвоено -- оно доступно только для чтения."

Как я могу перебирать myDict и меняем ценности?

591   8  

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

    Ничего не найдено.