Важная вещь HashSet<T>
в названии прямо здесь: это набор . Единственное, что вы можете сделать с одним набором, - это определить, каковы его члены, и проверить, является ли элемент членом.
Запрос о том, можете ли вы извлечь отдельный элемент (например set[45]
), неправильно понимает концепцию набора. Нет 45-го элемента набора. Предметы в наборе не имеют упорядочивания. Наборы {1, 2, 3} и {2, 3, 1} идентичны во всех отношениях, потому что они имеют одинаковое членство, и членство - это все, что имеет значение.
Несколько опасно перебирать объект, HashSet<T>
потому что это накладывает порядок на элементы в наборе. Этот порядок на самом деле не является свойством множества. Вы не должны полагаться на это. Если вам важно упорядочить элементы в коллекции, эта коллекция не является набором.
Наборы действительно ограничены и с уникальными членами. С другой стороны, они действительно быстрые.
SortedSet
структуру данных, либо противоречит тому, что вы говорите о порядке, а не свойстве набора, либо указывает на недопонимание со стороны команды разработчиков.HashSet
не определен, поэтому не полагайтесь на порядок итератора. Если вы повторяете набор, потому что вы делаете что-то с элементами в наборе, это не опасно, если вы не полагаетесь на что-либо, связанное с порядком. ASortedSet
имеет все свойстваHashSet
положительного порядка, ноSortedSet
не является производным отHashSet
; перефразируя, SortedSet - это упорядоченный набор отдельных объектов .Вот реальный пример того, где я использую
HashSet<string>
:Часть моей подсветки синтаксиса для файлов UnrealScript - это новая функция, которая выделяет комментарии в стиле Doxygen . Мне нужно определить, действительна ли команда
@
или,\
чтобы определить, отображать ли ее серым (действительный) или красным (недействительный). У меня есть списокHashSet<string>
всех допустимых команд, поэтому всякий раз, когда я нажимаю@xxx
токен в лексере, я использую его вvalidCommands.Contains(tokenText)
качестве проверки действительности O (1). Меня действительно ничего не волнует, кроме наличия команды в наборе допустимых команд. Давайте посмотрим на альтернативы, с которыми я столкнулся:Dictionary<string, ?>
: Какой тип использовать для значения? Значение бессмысленно, так как я просто собираюсь использоватьContainsKey
. Примечание. До .NET 3.0 это был единственный выбор для поиска O (1) - онHashSet<T>
был добавлен для 3.0 и расширен для реализацииISet<T>
для 4.0.List<string>
: Если я сохраню список отсортированным, я могу использоватьBinarySearch
, то есть O (log n) (не видел этого факта, упомянутого выше). Однако, поскольку мой список допустимых команд - это фиксированный список, который никогда не меняется, это никогда не будет более подходящим, чем просто ...string[]
: Опять же,Array.BinarySearch
дает производительность O (log n). Если список короткий, это может быть лучший вариант. Он всегда имеет меньше пространства над головой , чемHashSet
,Dictionary
илиList
. Даже при томBinarySearch
, что это не быстрее для больших сетов, но для маленьких стоит поэкспериментировать. У меня есть несколько сотен предметов, поэтому я пропустил это.источник
A
HashSet<T>
реализуетICollection<T>
интерфейс:А
List<T>
орудияIList<T>
, который расширяетICollection<T>
У HashSet есть заданная семантика, внутренне реализованная через хэш-таблицу:
Что получает HashSet, если он теряет поведение индекса / позиции / списка?
Добавление и извлечение элементов из HashSet всегда осуществляется самим объектом, а не с помощью индексатора, и близко к операции O (1) (List - O (1) add, O (1) - по индексу, O (n) - по поиску). /удалять).
Поведение HashSet можно сравнить с использованием
Dictionary<TKey,TValue>
только добавления / удаления ключей как значений и игнорирования самих значений словаря. Вы могли бы ожидать, что ключи в словаре не будут иметь повторяющихся значений, и в этом суть части «Установить».источник
Производительность была бы плохой причиной, чтобы выбрать HashSet вместо List. Что лучше отражает ваше намерение? Если порядок важен, Set (или HashSet) отсутствует. Точно так же, если дубликаты разрешены. Но есть много обстоятельств, когда мы не заботимся о порядке, и мы бы предпочли не иметь дубликатов - и тогда вы захотите сет.
источник
Performance would be a bad reason to choose HashSet over List
: Я просто не согласен с вами. Это своего рода говорит о том, что выбор Dictionray вместо двух Lists не помогает в производительности. Взгляните на следующую статьюstring[].Contains
иHashSet<string>.Contains
одинаково хорошо выражают свои намерения; причина выбора HashSet в том, что он будет работать намного быстрее.HashSet - это набор, реализованный путем хеширования. Набор - это набор значений, не содержащий повторяющихся элементов. Значения в наборе также обычно неупорядочены. Итак, нет, набор не может использоваться для замены списка (если вы не должны использовать набор в первую очередь).
Если вам интересно, для чего этот набор может быть полезен: очевидно, везде, где вы хотите избавиться от дубликатов. В качестве слегка надуманного примера предположим, что у вас есть список из 10.000 редакций программного проекта, и вы хотите узнать, сколько людей внесли свой вклад в этот проект. Вы можете использовать
Set<string>
и перебирать список ревизий и добавлять автора каждой ревизии в набор. Когда вы закончите итерацию, размер набора станет тем ответом, который вы искали.источник
HashSet будет использоваться для удаления повторяющихся элементов в коллекции IEnumerable. Например,
после запуска этих кодов uniqueStrings содержит {"abc", "ghjr", "yre", "obm", "qwrt", "vyeu"};
источник
Вероятно, наиболее распространенное использование хэш-наборов - это проверить, содержат ли они определенный элемент, что близко к операции O (1) для них (при условии достаточно сильной хеш-функции), в отличие от списков, для которых проверка на включение составляет O ( n) (и отсортированные множества, для которых это O (log n)). Поэтому, если вы много проверяете, содержится ли элемент в каком-либо списке, hahsset может улучшить производительность. Если вы выполняете итерацию только по ним, особой разницы не будет (итерация по всему набору - O (n), так же, как со списками и хеш-наборами, накладные расходы при добавлении элементов несколько выше).
И нет, вы не можете индексировать набор, что в любом случае не имеет смысла, потому что наборы не упорядочены. Если вы добавите какие-то предметы, набор не запомнит, какой из них был первым, а какой вторым и т. Д.
источник
HashSet<T>
представляет собой структуру данных в платформе .NET, которая способна представлять математический набор в виде объекта. В этом случае он использует хэш-коды (GetHashCode
результат каждого элемента) для сравнения равенства элементов набора.Набор отличается от списка тем, что он допускает только одно вхождение одного и того же элемента, содержащегося в нем.
HashSet<T>
просто вернется,false
если вы попытаетесь добавить второй идентичный элемент. Действительно, поиск элементов очень быстр (O(1)
время), поскольку внутренняя структура данных просто является хеш-таблицей.Если вам интересно, какой из них использовать, обратите внимание, что использование
List<T>
whereHashSet<T>
is подходящее является не самой большой ошибкой, хотя это может потенциально привести к проблемам, когда у вас есть нежелательные дублирующиеся элементы в вашей коллекции. Более того, поиск (поиск элементов) гораздо более эффективен - в идеалеO(1)
(для идеального размещения) вместоO(n)
времени - что довольно важно во многих сценариях.источник
List<T>
используются для хранения упорядоченных наборов информации. Если вы знаете относительный порядок элементов списка, вы можете получить к ним доступ в постоянное время. Однако, чтобы определить, где элемент находится в списке или проверить, существует ли он в списке, время поиска является линейным. С другой стороны, неHashedSet<T>
дает никаких гарантий порядка хранимых данных и, следовательно, обеспечивает постоянное время доступа к своим элементам.Как следует из названия,
HashedSet<T>
это структура данных, которая реализует семантику набора . Структура данных оптимизирована для реализации операций над множествами (т. Е. Объединение, Разница, Пересечение), что невозможно сделать так же эффективно, как при традиционной реализации List.Таким образом, выбор типа данных для использования на самом деле зависит от того, что вы пытаетесь сделать с вашим приложением. Если вас не волнует, как ваши элементы упорядочены в коллекции, и вы хотите только перечислить или проверить наличие, используйте
HashSet<T>
. В противном случае рассмотрите возможность использованияList<T>
или другой подходящей структуры данных.источник
Короче говоря - каждый раз, когда вы испытываете соблазн использовать Dictionary (или Dictionary, где S является свойством T), вам следует рассмотреть HashSet (или HashSet +, реализующий IEquatable на T, который приравнивается к S)
источник
В основном предполагаемом сценарии
HashSet<T>
следует использовать, когда вы хотите более конкретные операции над множествами для двух коллекций, чем предоставляет LINQ. Методы LINQ хотелиDistinct
,Union
,Intersect
иExcept
достаточно в большинстве случаев, но иногда могут потребоваться больше операций мелкозернистых, иHashSet<T>
обеспечивают:UnionWith
IntersectWith
ExceptWith
SymmetricExceptWith
Overlaps
IsSubsetOf
IsProperSubsetOf
IsSupersetOf
IsProperSubsetOf
SetEquals
Еще одно различие между LINQ и
HashSet<T>
«перекрывающимися» методами заключается в том, что LINQ всегда возвращает новыйIEnumerable<T>
, аHashSet<T>
методы изменяют исходную коллекцию.источник