2012-05-29 2 views
0

Я регулярно использую метод расширения LINQ ToDictionary, но мне интересно о производительности. Там нет параметра для определения мощности для словаря и со списком 100k пунктов или больше, это может стать проблемой:LINQ ToDictionary начальная емкость

IList<int> list = new List<int> { 1, 2, ... , 1000000 }; 
IDictionary<int, string> dictionary = list.ToDictionary<int, string>(x => x, x => x.ToString("D7")); 

ли реализация на самом деле взять list.Count и передает его в конструктор словарь? Или это изменение размера словаря достаточно быстро, так что мне не нужно беспокоиться об этом?

+0

Вы пробовали рассчитать длину его? – Ian

ответ

2

Выполняет ли реализация на самом деле список.Count и передает его в конструктор для словаря?

No.Согласно ILSpy, реализация в основном это:

Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>(comparer); 
foreach (TSource current in source) 
{ 
    dictionary.Add(keySelector(current), elementSelector(current)); 
} 
return dictionary; 

Если вы профиль ваш код и определить, что ToDictionary операция узким местом, его тривиальным, чтобы сделать свою собственную функцию на основе вышеприведенного кода.

+0

Спасибо за ваш ответ. В этом случае я попытаюсь создать пользовательское расширение для создания словарей. – Franky

2

Выполняет ли реализация фактически список.Count и передает его конструктору для словаря?

Это деталь реализации, и это не должно иметь значения для вас.

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

Ну, я не знаю. Только вы знаете, действительно ли это является узким местом в вашей заявке, и является ли приемлемая производительность. Если вы хотите знать, достаточно ли это, напишите код и время его. Как говорит Эрик Липперт, если вы хотите знать, как быстро две лошади, вы бросаете их в гонку друг против друга или вы спрашиваете случайных незнакомых людей в Интернете, какой из них быстрее?

Это говорит о том, что мне очень тяжело изображать это узкое место в любом реалистичном приложении. Если добавление элементов в словарь является узким местом в вашем приложении, вы делаете что-то неправильно.

+0

Обычно да, призыв к ToDictionary не должен быть узким местом, но мне нужно импортировать миллионы данных и поддерживать в словарях впоследствии создавать ссылки. Сроки этого, как предложил Ян, скажут мне, сколько времени это займет, но мне было интересно, может ли повторная реализация ToDictionary ускорить мое приложение, если я укажу емкость? – Franky

+0

Похоже, вы делаете единовременный импорт? Как это может быть узким местом? Но, опять же, моя первоначальная точка остается. Либо это достаточно быстро, как есть (ваша первая лошадь), или это не так, и вы должны закодировать свою версию словаря (свою вторую лошадь) и посмотреть, какая из двух лошадей достаточно быстро для ваших целей. Я сомневаюсь, что вы увидите большую часть разницы в производительности, начиная с двух. – jason

+0

@Franky - Я уверен, что класс словаря удваивается при каждом изменении размера, поэтому у вас будет только изменение размера log2 (n), поэтому в случае 1 000 000 записей будет доступно только около 20 изменений. Что касается производительности на этом, я не уверен, но, как сказал акатакритос, должно быть тривиально реализовать перегрузку, которая принимает размер. –

0

Я не знаю, как изменить размер словаря, но проверка реализации с помощью dotPeek.exe предполагает, что реализация не принимает длину списка.

Что код в основном делает:

  • создать новый словарь
  • перебирать последовательность и добавить элементы

Если вы нашли это узкое место, было бы тривиально, чтобы создать свой собственный метод расширения ToDictionaryWithCapacity, который работает над тем, что может быть рассчитано по длине без повторения всего этого.

Только что просмотрено Dictionary осуществления. В основном, когда он начинает заполняться, внутренний список изменяется, грубо удваивая его до близкого числа. Так что это не должно происходить слишком часто.

0

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

0

Выполняет ли реализация фактически список.Count и передает его конструктору для словаря?

Это не так. Это потому, что вызывающий граф() перечислил источник, а затем добавив его в словарь, будет перечислить источник во второй раз. Не рекомендуется переименовывать источник дважды, например, это не удастся для DataReaders.

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

Метод Dictionary.Resize используется для расширения словаря. Он выделяет новый словарь и копирует существующие элементы в новый словарь (используя Array.Copy). Размер словаря увеличивается с шагом числа.

Это не самый быстрый способ, но достаточно быстрый, если вы не знаете размер.

+0

'Count' и' Count() 'не совпадают. – leppie

+0

Леппи, ты прав. Но ToDictionary() - это метод расширения для IEnumerable, поэтому Count недоступен. Count() также является методом расширения для IEnumerable. –

+0

@ CarstenSchütte Иногда методы расширения оптимизируются для коллекций, которые знают их «Count» или индексируются. Пример: http://stackoverflow.com/a/18200099/543814. – Timo