В чем разница между HashSet <T> и List <T>?

Можете ли вы объяснить, в чем разница между HashSet<T> и List<T> в .NET?

Может быть, вы можете объяснить на примере, в каких случаях HashSet<T> следует отдавать предпочтение List<T>?

Ответ 1

В отличие от списка <>...

  1. HashSet - это список без повторяющихся членов.

  2. Поскольку HashSet ограничен только уникальными записями, внутренняя структура оптимизирована для поиска (по сравнению со списком) - это значительно быстрее

  3. Добавление в HashSet возвращает логическое значение - false, если добавление не выполняется из-за того, что оно уже существует в Set

  4. Может выполнять математические операции над множествами: объединение/пересечение /IsSubsetOf и т.д.

  5. HashSet не реализует IList только ICollection

  6. Вы не можете использовать индексы с HashSet, только перечислители.

Основная причина использования HashSet может быть связана с тем, что вы заинтересованы в выполнении операций Set.

Дано 2 набора: hashSet1 и hashSet2

 //returns a list of distinct items in both sets
 HashSet set3 = set1.Union( set2 );

вылетает по сравнению с эквивалентной операцией с использованием LINQ. Это также аккуратнее писать!

Ответ 2

A HashSet<T> - это класс, предназначенный для поиска O(1) поиска для сдерживания (т.е. содержит ли этот набор конкретный объект и быстро сообщает ответ).

A List<T> - это класс, предназначенный для создания коллекции с O(1) случайным доступом, чем динамически динамически (подумайте о динамическом массиве). Вы можете проверить сдерживание в O(n) времени (если список не отсортирован, тогда вы можете выполнить двоичный поиск в O(log n) время).

Возможно, вы можете объяснить с помощью примера, в каких случаях HashSet<T> следует предпочесть против List<T>

Если вы хотите проверить сдерживание в O(1).

Ответ 3

Чтобы быть более точным, давайте продемонстрируем примеры,

Вы не можете использовать 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

Ответ 4

Используйте List<T>, если хотите:

  • Сохранение коллекции элементов в определенном порядке.

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

Используйте Hashset<T>, если хотите:

  • Быстро узнать, содержится ли какой-либо объект в коллекции.

Если вы знаете имя вещи, которую хотите найти, Lookup - это O(1) (это часть "Хеш" ). Он не поддерживает порядок, подобный List<T>, и вы не можете хранить дубликаты (добавление дубликата не влияет на часть "Установить" ).

Примером того, когда использовать Hashset<T>, было бы, если вы хотите узнать, является ли слово, играемое в игре Scrabble, действительным словом на английском (или другом языке). Еще лучше было бы, если бы вы хотели создать веб-сервис, который будет использоваться всеми экземплярами онлайн-версии такой игры.

A List<T> будет хорошей структурой данных для создания табло для отслеживания очков игроков.

Ответ 5

Список - это упорядоченный список.

  • доступ к целочисленному индексу
  • может содержать дубликаты
  • имеет предсказуемый порядок

HashSet - это набор. Это:

  • Может блокировать повторяющиеся элементы (см. Добавить (T))
  • Не гарантирует порядок элементов в наборе
  • Операции, которые вы ожидаете от набора, например, IntersectWith, IsProperSubsetOf, UnionWith.

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

Ответ 6

Список не обязательно уникален, а hashset - для одного.

Ответ 7

Список - это упорядоченный набор объектов типа T, который в отличие от массива, который вы можете добавить и удалить записи.

Вы бы использовали список, в котором вы хотите ссылаться на члены в том порядке, в котором вы их сохранили, и вы получаете доступ к ним по позиции, а не по самому элементу.

A HashSet похож на словарь, что сам элемент является ключом, а также значением, порядок не гарантируется.

Вы бы использовали HashSet, где вы хотите проверить, что объект находится в коллекции

Ответ 8

Если вы решите применить эти структуры данных к фактическому использованию в управляемой данными разработке, HashSet ОЧЕНЬ полезен при тестировании репликации по источникам адаптера данных, для очистки и миграции данных.

Кроме того, если использовать класс DataAnnotations, можно реализовать логику Key в свойствах класса и эффективно управлять естественным индексом (кластерным или нет) с помощью HashSet, где это будет очень сложно в реализации List.

Сильным вариантом для использования списка является реализация обобщений для нескольких сред в Model View, например отправка списка классов в MVC View для помощника DropDownList, а также для отправки в виде конструкции JSON через WebApi. Этот список позволяет типичную логику сбора классов и сохраняет гибкость для более "интерфейсного" подхода к вычислению единой модели представления для разных сред.