Надеюсь, простой вопрос о модификации словарей в C # - PullRequest
0 голосов
/ 29 ноября 2008

У меня есть огромный словарь пустых значений в переменной с именем current, например:

struct movieuser {blah blah blah}
Dictionary<movieuser, float> questions = new Dictionary<movieuser, float>();

Итак, я перебираю этот словарь и мне нужно заполнить «ответы», вот так:

for(var k = questions.Keys.GetEnumerator();k.MoveNext(); )
{
    questions[k.Current] = retrieveGuess(k.Current.userID, k.Current.movieID);
}

Теперь, это не работает, потому что я получаю InvalidOperationException от попытки изменить словарь, по которому я зацикливаюсь. Однако вы можете видеть, что код должен работать нормально - поскольку я не добавляю и не удаляю какие-либо значения, я просто изменяю значение. Однако я понимаю, почему он боится моих попыток сделать это.

Каков предпочтительный способ сделать это? Я не могу найти способ перебрать словарь БЕЗ использования итераторов.

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

Спасибо, Dave

Ответы [ 3 ]

2 голосов
/ 29 ноября 2008

Ответ Мэтта, сначала получение ключей, отдельно - правильный путь. Да, будет некоторая избыточность - но это будет работать. Я бы взял рабочую программу, которую легко отлаживать и поддерживать по сравнению с эффективной программой, которая либо не будет работать, либо ее сложно поддерживать в любой день.

Не забывайте, что если вы сделаете MovieUser ссылочным типом, массив будет размером только с столько ссылок, сколько у вас есть пользователей - это довольно мало. Миллион пользователей займет всего 4 МБ или 8 МБ на x64. Сколько пользователей у вас действительно есть?

Ваш код должен быть примерно таким:

IEnumerable<MovieUser> users = RetrieveUsers();

IDictionary<MovieUser, float> questions = new Dictionary<MovieUser, float>();
foreach (MovieUser user in users)
{
    questions[user] = RetrieveGuess(user);
}

Если вы используете .NET 3.5 (и поэтому можете использовать LINQ), это еще проще:

IDictionary<MovieUser, float> questions = 
    RetrieveUsers.ToDictionary(user => user, user => RetrieveGuess(user));

Обратите внимание, что если RetrieveUsers() может транслировать список пользователей из его источника (например, из файла), то он все равно будет эффективен, так как вам никогда не нужно знать о более чем одном из них одновременно, когда вы заполняете словарь.

Несколько комментариев к остальной части вашего кода:

  • Кодовые соглашения имеют значение. Используйте названия ваших типов и методов с заглавными буквами, чтобы они соответствовали другому .NET-коду.
  • Вы не звоните Dispose на IEnumerator<T>, полученном при звонке на GetEnumerator. Если вы просто используете foreach, ваш код будет проще и безопаснее.
  • MovieUser почти наверняка должен быть классом. У вас есть действительно веская причина сделать его структурой?
2 голосов
/ 29 ноября 2008

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

foreach(var key in someListOfKeys)
{
    questions.Add(key, retrieveGuess(key.userID, key.movieID);
}
0 голосов
/ 29 ноября 2008

хранит ключи словаря во временной коллекции, затем перебирает временную коллекцию и использует значение ключа в качестве параметра индексатора. Это должно помочь вам обойти исключение.

...