Более быстрые альтернативы .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 в конце, чтобы изменить его размер без выделения. Это заканчивается значительно быстрее.

Другие плакаты, вероятно, правильны, хотя вы можете достичь этой цели каким-то другим способом, например, с использованием хэш-набора в первую очередь или с сохранением параллельных коллекций, в которых каждый раз содержит только отдельные элементы. Смещение небольших затрат на вставку/удаление, так что для получения отдельного набора не требуется никакого времени.