2015-01-13 5 views
3

У меня есть следующий код на C#, где vector - это [строка, двойной] тип словаря. Я хочу разделить все значения в этом словаре на значение «величина». Теперь, мой наивный первый код был следующим:Разделение всех значений словаря на значение

foreach (var key in vector.Keys) 
{ 
    vector[key] = vector[key]/magnitude; 
} 

Который бросает исключение, заявив, что коллекция была изменена в Еогеаспе. Я могу создать второй словарь для записи результирующих значений, но я не хочу этого.

Есть ли более простой способ сделать это, например, используя методы, которые работают со всеми значениями словаря, например, следующие?

vector.Values().Aggreagate(), vector.Values().Average() 
+0

Вы хотите изменить словарь? Я спрашиваю, потому что вы не упомянули об этом. Если вы просто хотите вычислить значение в соответствии со значениями словаря, используйте локальную переменную. –

ответ

8

простейший способ сделать это просто скопировать список ключей перед тем итерация:

foreach (var key in vector.Keys.ToList()) 
{ 
    vector[key] = vector[key]/magnitude; 
} 

Или:

foreach (var entry in vector.ToList()) 
{ 
    vector[entry.Key] = entry.Value/magnitude; 
} 

(Это позволяет избежать двойной поиск, но скопирует больше данных, конечно.)

Немного постыдно, что мода Игнорирование значения существующей записи рассматривается как изменение, которое, по общему признанию, мешает вам продолжать перебирать ключи.

Альтернатива будет иметь изменяемый тип обертки в качестве значения, то вы можете использовать:

foreach (var wrapper in vector.Values) 
{   
    wrapper.Value = wrapper.Value/10; 
} 

Что бы не изменяющее словаря на всех - только те объекты, которые словарь относится к. Я лично не делал этого в большинстве случаев, но это может быть может.

+0

Второе решение, которое вы говорите, «но скопирует больше данных, конечно». Почему - как первые, так и второй создают мелкий список ссылок одной и той же длины? – weston

+1

@weston: Нет, первый будет просто скопировать ключи.Второй будет копировать полный 'KeyValuePair <,>' (который является структурой) в каждом случае. –

+0

Ах не понял, была ли структура. – weston

4

Это, конечно, потому, что вы изменяете словарь во время итерации. Вы можете попробовать Перебор копию Keys вместо фактического сбора

foreach (var key in vector.Keys.ToList()) 
{ 
    vector[key] = vector[key]/magnitude; 
} 
3

Вы могли бы избежать изменений коллекции, скопировав его следующим образом.

var CopiedKeys = vector.Keys.ToList(); 
foreach (var key in CopiedKeys) 
{ 
    vector[key] = vector[key]/magnitude; 
} 
+0

Вы не изменили его сами? –

+1

Нет, сначала создается копия всех ключей. Копия коллекции ключей имеет те же значения, что и вектор, но они разные объекты. – Codor

+0

А, ладно, я понимаю. Я подумал, зачем нам копировать ключи, если мы их даже не меняем. Теперь я понимаю, что мы действительно меняем ключи. –

2
 dictionary = dictionary.ToDictionary(x => x.Key, x => x.Value/magnitude); 
1

Альтернатива может быть использована инкрементным итератором

int magnitude = 2; 
for (int index = 0; index < vector.Count; index++) 
{ 
    String key = vector.ElementAt(index).Key; 
    vector[key] = vector[key]/magnitude; 
} 
0

Один из самых простых способов является использование обычным для итерации, как этот образец:

 for (int i = 0; i < vector.Keys.Count; i++) 
     { 
      string key = vector.Keys.ElementAt(i); 
      vector[key] /= magnitude; 
     } 

если вы хотите использовать методы Linq, вы можете использовать этот код:

vector=vector 
      .Select(x=> new KeyValuePair<string,double>(x.Key,x.Value/magnitude)) 
      .ToDictionary(x=>x.Key,x=>x.Value); 
+0

Как и реакция Мэтта Гордона, но превосходное использование оператора/=. –

Смежные вопросы