Можете ли вы объяснить, в чем разница между HashSet<T>
и List<T>
в .NET?
Может быть, вы можете объяснить на примере, в каких случаях HashSet<T>
следует отдавать предпочтение List<T>
?
Можете ли вы объяснить, в чем разница между HashSet<T>
и List<T>
в .NET?
Может быть, вы можете объяснить на примере, в каких случаях HashSet<T>
следует отдавать предпочтение List<T>
?
В отличие от списка <>...
HashSet - это список без повторяющихся членов.
Поскольку HashSet ограничен только уникальными записями, внутренняя структура оптимизирована для поиска (по сравнению со списком) - это значительно быстрее
Добавление в HashSet возвращает логическое значение - false, если добавление не выполняется из-за того, что оно уже существует в Set
Может выполнять математические операции над множествами: объединение/пересечение /IsSubsetOf и т.д.
HashSet не реализует IList только ICollection
Вы не можете использовать индексы с HashSet, только перечислители.
Основная причина использования HashSet может быть связана с тем, что вы заинтересованы в выполнении операций Set.
Дано 2 набора: hashSet1 и hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
вылетает по сравнению с эквивалентной операцией с использованием LINQ. Это также аккуратнее писать!
A HashSet<T>
- это класс, предназначенный для поиска O(1)
поиска для сдерживания (т.е. содержит ли этот набор конкретный объект и быстро сообщает ответ).
A List<T>
- это класс, предназначенный для создания коллекции с O(1)
случайным доступом, чем динамически динамически (подумайте о динамическом массиве). Вы можете проверить сдерживание в O(n)
времени (если список не отсортирован, тогда вы можете выполнить двоичный поиск в O(log n)
время).
Возможно, вы можете объяснить с помощью примера, в каких случаях
HashSet<T>
следует предпочесть противList<T>
Если вы хотите проверить сдерживание в O(1)
.
Чтобы быть более точным, давайте продемонстрируем примеры,
Вы не можете использовать HashSet, как в следующем примере.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
приведет к ошибке:
Невозможно применить индексирование с [] к выражению типа 'System.Collections.Generic.HashSet'
Вы можете использовать оператор foreach:
foreach (var item in hashSet1)
Console.WriteLine(item);
Вы не можете добавить дублированные элементы в HashSet, тогда как List позволяет вам сделать это и в то время как вы добавляете элемент в HashSet, вы можете проверить, содержит ли он элемент или нет.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet имеет некоторые полезные функции, такие как IntersectWith
, UnionWith
, IsProperSubsetOf
, ExceptWith
, SymmetricExceptWith
и т.д.
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
Кстати, порядок не сохраняется в HashSets. В этом примере мы добавили элемент "2" последним, но он находится во втором порядке:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
Используйте List<T>
, если хотите:
Если вам известен индекс нужного элемента (а не значение самого элемента), то поиск O(1)
. Если вы не знаете индекс, поиск элемента занимает больше времени, O(n)
для несортированной коллекции.
Используйте Hashset<T>
, если хотите:
Если вы знаете имя вещи, которую хотите найти, Lookup - это O(1)
(это часть "Хеш" ). Он не поддерживает порядок, подобный List<T>
, и вы не можете хранить дубликаты (добавление дубликата не влияет на часть "Установить" ).
Примером того, когда использовать Hashset<T>
, было бы, если вы хотите узнать, является ли слово, играемое в игре Scrabble, действительным словом на английском (или другом языке). Еще лучше было бы, если бы вы хотели создать веб-сервис, который будет использоваться всеми экземплярами онлайн-версии такой игры.
A List<T>
будет хорошей структурой данных для создания табло для отслеживания очков игроков.
Список - это упорядоченный список.
HashSet - это набор. Это:
Список более подходит, если вы хотите получить доступ к своей коллекции, как если бы это был массив, к которому вы могли добавлять, вставлять и удалять элементы. HashSet - лучший выбор, если вы хотите рассматривать свою коллекцию как "мешок" предметов, в которых порядок не важен или когда вы хотите сравнить его с другими наборами, используя операции, такие как IntersectWith или UnionWith.
Список не обязательно уникален, а hashset - для одного.
Список - это упорядоченный набор объектов типа T, который в отличие от массива, который вы можете добавить и удалить записи.
Вы бы использовали список, в котором вы хотите ссылаться на члены в том порядке, в котором вы их сохранили, и вы получаете доступ к ним по позиции, а не по самому элементу.
A HashSet похож на словарь, что сам элемент является ключом, а также значением, порядок не гарантируется.
Вы бы использовали HashSet, где вы хотите проверить, что объект находится в коллекции
Если вы решите применить эти структуры данных к фактическому использованию в управляемой данными разработке, HashSet ОЧЕНЬ полезен при тестировании репликации по источникам адаптера данных, для очистки и миграции данных.
Кроме того, если использовать класс DataAnnotations, можно реализовать логику Key в свойствах класса и эффективно управлять естественным индексом (кластерным или нет) с помощью HashSet, где это будет очень сложно в реализации List.
Сильным вариантом для использования списка является реализация обобщений для нескольких сред в Model View, например отправка списка классов в MVC View для помощника DropDownList, а также для отправки в виде конструкции JSON через WebApi. Этот список позволяет типичную логику сбора классов и сохраняет гибкость для более "интерфейсного" подхода к вычислению единой модели представления для разных сред.