Чем HashSet лучше List когда нужны только уникальные значения?
Учу C# и наткнулся на HashSet<T>. Не очень понимаю, зачем он нужен, если есть List<T>. У меня задача — собрать список ID пользователей без повторов. Сейчас делаю так:
var ids = new List<int>();
foreach (var id in input)
{
if (!ids.Contains(id))
ids.Add(id);
}
Выглядит костыльно. Есть способ лучше? И вообще, чем HashSet отличается от List?
2 ответа
HashSet<T> — это коллекция уникальных элементов. Она сама не даёт добавить дубликат, поэтому ваш цикл с проверкой Contains не нужен:
var ids = new HashSet<int>();
foreach (var id in input)
ids.Add(id); // дубликаты просто игнорируются
// или ещё короче:
var unique = new HashSet<int>(input);
Главное отличие от List — это скорость поиска. List.Contains перебирает все элементы по очереди — это O(n). HashSet.Contains использует хеши и работает за O(1) в среднем. На больших данных разница огромная.
Ключевые различия:
List<T> |
HashSet<T> |
|
|---|---|---|
| Дубликаты | разрешены | запрещены |
| Порядок | сохраняется | не гарантируется |
Поиск Contains |
O(n) | O(1) |
| Доступ по индексу | есть list[i] |
нет |
Берите List, когда важен порядок и индексы. Берите HashSet, когда нужна уникальность и быстрая проверка «есть ли элемент».
Бонус — у HashSet есть операции множеств:
var a = new HashSet<int> { 1, 2, 3 };
var b = new HashSet<int> { 2, 3, 4 };
a.IntersectWith(b); // a теперь { 2, 3 }
Если коротко: HashSet нужен именно для уникальности и быстрых проверок «содержится / не содержится».
Один нюанс новичкам: HashSet не хранит порядок добавления. Если вам важно, чтобы элементы шли в том же порядке, в каком пришли, но при этом без дублей — тогда либо List + проверка, либо Distinct() из LINQ:
using System.Linq;
var unique = input.Distinct().ToList(); // порядок сохраняется