C # Установить коллекцию?

488

Кто-нибудь знает, есть ли хороший эквивалент Setколлекции Java в C #? Я знаю, что вы можете имитировать набор, используя a Dictionaryили a HashTable, заполняя, но игнорируя значения, но это не очень элегантный способ.

Омар Кохеджи
источник

Ответы:

142

Попробуйте HashSet :

Класс HashSet (Of T) обеспечивает высокопроизводительные операции над множествами. Набор - это коллекция, которая не содержит повторяющихся элементов и элементы которой расположены в произвольном порядке ...

Емкость объекта HashSet (Of T) - это количество элементов, которые объект может содержать. Емкость объекта HashSet (Of T) автоматически увеличивается при добавлении элементов в объект.

Класс HashSet (Of T) основан на модели математических множеств и обеспечивает высокопроизводительные операции над множествами, аналогичные доступу к ключам из словарей (Of TKey, TValue) или коллекций Hashtable . Проще говоря, класс HashSet (Of T) можно рассматривать как коллекцию Dictionary (Of TKey, TValue) без значений.

Коллекция HashSet (Of T) не отсортирована и не может содержать повторяющиеся элементы ...

Леан Новаш
источник
8
К сожалению, HashSets не были добавлены до недавнего времени. Если вы работаете в более старой версии фреймворка, вам придется придерживаться своего словаря <> или Hashtable.
Грег Д
413

Если вы используете .NET 3.5, вы можете использовать HashSet<T>. Это правда, что .NET не обслуживает наборы так же хорошо, как Java.

В PowerCollections Wintellect может помочь тоже.

Джон Скит
источник
16
Я подозреваю, что Set является ключевым словом в некоторых языках, что может вызвать проблемы.
Джон Скит
3
@Manish: нет, это не так. Смотрите раздел 2.4.3 спецификации C # 3. Это имеет особое значение только для свойств.
Джон Скит
28
Причина, по которой он называется HashSet, а не просто Set, та же, что и в Java: «Set» описывает интерфейс, тогда как «HashSet» описывает реализацию, в частности, это Set, поддерживаемый Hash Map. Таким образом, мы знаем (или должны строго ожидать), что вставка и доступ должны занимать время доступа O (1), а не «LinkedListSet», который заставил бы нас ожидать, что вставка и доступ займут время O (n).
Дэвид Саутер
5
что вы имеете в виду «.NET не обслуживает наборы так же хорошо, как Java»? Является ли этот набор каким-то несовершенным по сравнению с Java?
Луи Рис
34
@Louis: о каком наборе ты говоришь? Java имеет множество различных реализаций Set для различных ситуаций. .NET имел один в .NET 3.5 (HashSet) и два в .NET 4 (HashSet и SortedSet). Тот факт, что нам пришлось ждать до .NET 3.5 для начала, довольно удивителен.
Джон Скит
26

Если вы используете .NET 4.0 или более позднюю версию:

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

Дерек W
источник
13

Я использую обертку вокруг Dictionary<T, object>, сохраняя нули в значениях. Это дает O (1) добавление, поиск и удаление ключей, и для всех намерений и целей действует как набор.

thecoop
источник
2
Вы должны иметь ввиду, что он примерно эквивалентен std :: unordered_set. std :: set упорядочен. Например, вы можете быстро найти начальную и конечную точки диапазона и выполнить итерацию от начала до конца, посещая элементы в порядке расположения ключей. SortedDictionary это примерно эквивалентен станд :: набора.
doug65536
11

Посмотрите на PowerCollections на CodePlex. Помимо Set и OrderedSet у него есть несколько других полезных типов коллекций, таких как Deque, MultiDictionary, Bag, OrderedBag, OrderedDictionary и OrderedMultiDictionary.

Для большего количества коллекций есть также C5 Generic Collection Library .

DPAn
источник
-5

Я знаю, что это старый поток, но я столкнулся с той же проблемой и обнаружил, что HashSet очень ненадежен, поскольку при одинаковом начальном значении GetHashCode () возвращает разные коды. Итак, я подумал, почему бы просто не использовать List и скрыть метод add следующим образом

public class UniqueList<T> : List<T>
{
    public new void Add(T obj)
    {
        if(!Contains(obj))
        {
            base.Add(obj);
        }
    }
}

Поскольку List использует метод Equals исключительно для определения равенства, вы можете определить метод Equals для вашего типа T, чтобы убедиться, что вы получите желаемые результаты.

Боб Хек
источник
13
Причина, по которой вы не захотите использовать это, заключается List.Containsв O(n)сложности, которая означает, что ваш Addметод теперь также становится O(n)сложным. Предполагая, что внутренняя коллекция не должна быть изменена, Addдля обоих Listи HashMapдолжна иметь O(1)сложность. TLDR: это сработает, но это хакерское и менее эффективное.
Ричард Марскелл - Дракир
6
Конечно, если ваши объекты не возвращают подходящее значение для GetHashCode, вы не должны помещать их в контейнер на основе хеша. Было бы лучше исправить GetHashCode, чем использовать менее эффективный контейнер.
bmm6o