Более быстрые альтернативы .Distinct()
Я делаю видеоигру, где производительность имеет решающее значение.
Я использую метод расширения .Distinct(), чтобы получить уникальное значение из списка.
Есть ли более быстрый способ сделать это? (даже если это означает, что у вас еще много строк кода)
Ответы
Ответ 1
.Distinct
- вызов O(n)
.
Вы не можете ускорить это.
Однако вы должны убедиться, что ваш GetHashCode
(и, в меньшей степени, Equals
) как можно быстрее.
В зависимости от вашего сценария вы можете заменить List<T>
на HashSet<T>
, что не позволит в первую очередь вставлять дубликаты. (но есть O(1)
вставка)
Тем не менее Всегда профилируйте свой код перед тем, как перейти к выводам о том, что должно быть быстрее.
Ответ 2
Должен ли быть список?
Можно ли переключиться с List на HashSet? HashSet не позволяет вставлять объекты в список более чем один раз, поэтому Distinct уже сделан.
Ответ 3
Если вы можете сделать отдельный, вы можете сделать это очень быстро и с нулевым распределением, сначала используя Array.Sort
, а затем:
TSource oldV = source[0];
int pos = 1;
for (int i = 1; i < source.Count; i++)
{
var newV = source[i];
source[pos] = newV;
if (!eqComparer.Equals(newV, oldV))
{
pos++;
}
oldV = newV;
}
//pos now == the new size of the array
Затем вам нужно будет отслеживать размер меньшего размера массива или использовать Array.resize(но это будет выделение нового массива)
В качестве альтернативы, если вы выполняете этот же подход с помощью List<T>
, вы можете вызвать RemoveRange
в конце, чтобы изменить его размер без выделения. Это заканчивается значительно быстрее.
Другие плакаты, вероятно, правильны, хотя вы можете достичь этой цели каким-то другим способом, например, с использованием хэш-набора в первую очередь или с сохранением параллельных коллекций, в которых каждый раз содержит только отдельные элементы. Смещение небольших затрат на вставку/удаление, так что для получения отдельного набора не требуется никакого времени.