Почему в C# есть HashSet, а не Set?

Старый вопрос

Насколько я понимаю, С# в некотором смысле имеет типы HashSet и set. Я понимаю, что такое HashSet. Но почему set это отдельное слово? Почему не каждый набор HashSet<Object>?

Новый вопрос

Почему в C# нет универсального типа Set, аналогичного типу Dictionary? С моей точки зрения, я хотел бы иметь набор со стандартной производительностью поиска/добавления/удаления. Мне было бы все равно, реализовано ли это с помощью хэшей или чего-то еще. Так почему бы не создать класс набора, который фактически был бы реализован как HashSet в этой версии C#, но, возможно, несколько иначе в будущей версии?

Или почему хотя бы не интерфейс ISet?

Отвечать

Узнал спасибо всем, кто ответил ниже: ICollection реализует многое из того, что вы ожидаете от ISet. Однако, с моей точки зрения, ICollection реализует IEnumerable, тогда как наборы не обязательно должны быть перечисляемыми --- пример: набор действительных чисел от 1 до 2 (более того, наборы могут генерироваться динамически). Я согласен, что это незначительная тирада, поскольку «обычным программистам» редко нужны несчетные наборы.

Хорошо, думаю, я понял. HashSet должно было называться Set, но слово Set в каком-то смысле зарезервировано. В частности, создатели архитектуры .NET хотели иметь согласованный набор (sic!) классов для разных языков. Это означает, что каждое имя стандартного класса не должно совпадать ни с одним ключевым словом в языках .NET. Однако слово Set используется в VB.NET, который на самом деле нечувствителен к регистру (не так ли?), поэтому, к сожалению, здесь нет места для маневра.

Тайна раскрыта :)

Эпилог

Новый ответ Алекса Ю. ссылается на страницу MSDN, который описывает будущий интерфейс .NET 4.0 ISet, который ведет себя почти так, как я думал, и реализован HashedSet. Счастливый конец.


person ilya n.    schedule 21.06.2009    source источник
comment
в качестве примечания: в .NET есть несколько internal class Set. источник ссылки   -  person Slai    schedule 21.06.2017


Ответы (7)


(На ваш первоначальный вопрос о set был дан ответ. IIRC, «набор» - это слово с самыми разными значениями в английском языке ... очевидно, это также влияет на вычисления.)

Я думаю, что это нормально иметь HashSet<T> с таким именем, но я бы определенно приветствовал интерфейс ISet<T>. Учитывая, что HashSet<T> появился только в .NET 3.5 (что само по себе было неожиданно), я подозреваю, что в конечном итоге мы можем получить более полную коллекцию основанных на множестве типов. В частности, в некоторых случаях будет полезен эквивалент LinkedHashSet в Java, который поддерживает порядок вставки.

Честно говоря, интерфейс ICollection<T> на самом деле покрывает большую часть того, что вы хотели бы видеть в ISet<T>, так что, возможно, это и не требуется. Однако вы могли бы возразить, что основная цель набора (которая в основном связана с сдерживанием и только косвенно с возможностью перебора элементов) не совсем то же самое, что и коллекция. Это сложно. На самом деле истинно математический набор может не быть повторяемым или счетным — например, у вас может быть «набор действительных чисел от 1 до 2». Если бы у вас был числовой тип произвольной точности, счет был бы бесконечным, и повторение его не имело бы никакого смысла.

Точно так же идея «добавления» к набору не всегда имеет смысл. Изменчивость - сложная задача при именовании коллекций :(

РЕДАКТИРОВАТЬ: Хорошо, отвечая на комментарий: ключевое слово set никоим образом не является наследием Visual Basic. Это операция, которая устанавливает значение свойства, а get извлекает операцию. Это не имеет ничего общего с идеей множества как операции.

Представьте, что вместо этого ключевые слова на самом деле были fetch и assign, например.

// Not real code!
public int Foo
{
    fetch
    {
        return fooField;
    } 
    assign
    {
        fooField = value;
    } 
}

Там цель ясна? Теперь реальный эквивалент этого в C# просто

public int Foo
{
    get
    {
        return fooField;
    } 
    set
    {
        fooField = value;
    } 
}

Итак, если вы пишете:

x = y.Foo;

который будет использовать get часть свойства. Если вы пишете:

y.Foo = x;

который будет использовать часть set.

Так понятнее?

person Jon Skeet    schedule 21.06.2009
comment
На самом деле, я до сих пор не понимаю оригинальную вещь о наборе. - person ilya n.; 21.06.2009
comment
Из связанного сообщения самое близкое, что я получаю, это то, что есть какое-то устаревшее слово Set из Visual Basic. - person ilya n.; 21.06.2009
comment
Извините, я был неясен. Я знаком с парой ключевых слов set/get, но я знаю, что они пишутся в нижнем регистре, и я считаю, что C# чувствителен к регистру, поэтому я не думал, что это имеет отношение к классу Set. Но Set, являющийся зарезервированным ключевым словом из VB.NET, объясняет это (до сих пор я не знал, что C # и VB связаны, но теперь я думаю, что они есть) - person ilya n.; 21.06.2009
comment
Я знал об ICollection, но, думаю, для меня как математика коллекции и множества с самого начала были очень разными. Теперь, когда я думаю об этом, я согласен с тем, что ICollection похож на то, как люди на самом деле используют наборы в программировании. Однако, если взять пример из математики, у множеств есть более интересные примеры. Например, рассмотрим множество [0; 1] \союз [2; 3) \союз [7; +\infty]. Этот набор легко запрограммировать как упорядоченный набор, но его никогда нельзя запрограммировать как набор. - person ilya n.; 21.06.2009
comment
Исправление: его никогда нельзя запрограммировать как список, но я подозреваю, что ICollection включает в себя метод, аналогичный ToArray(). Это можно было бы рассматривать как коллекцию, которую нельзя повторять, но я думаю, что это новая идея по сравнению с тем, к чему привыкли люди. - person ilya n.; 21.06.2009
comment
Я думаю, что пропустил часть вашего ответа, где вы говорите то же самое, что и я, о том, что множества не обязательно счетны. Извиняюсь, что повторяю как мое изобретение. - person ilya n.; 21.06.2009
comment
Что касается изменчивости и сложения, то наборы очень опасны в этом отношении, поскольку real_set.Add(5), а также real_set.Plus(5) можно понимать как все множество, сдвинутое на 5 (то есть новое множество, элементы которого точно x+5 для x, являющегося элементом some_set) - person ilya n.; 21.06.2009
comment
Да, в основном вам нужно очень четко понимать, о какой концепции набора вы говорите. Я думаю, что всегда использовал бы что-то вроде смещения для последней операции, о которой вы говорите, но я согласен, что это вызывает беспокойство. - person Jon Skeet; 21.06.2009
comment
На самом деле, translate(Vector v) будет математическим стандартом... конечно, он может не работать с i18n. - person ilya n.; 21.06.2009
comment
Обновление Конечно, в 2010 году вышла версия 4.0 .NET с интерфейсом ISet<T>, реализованным с помощью HashSet<T>, и новым классом SortedSet<T>. - person Jeppe Stig Nielsen; 02.05.2013

Набора<T> нет. Этот сообщение в блоге команды BCL содержит много подробностей о HashSet, включая не совсем убедительное обсуждение включения хэша в имя. Я подозреваю, что не всем в команде BCL понравилось решение использовать имя HashSet<T>.

person ScottS    schedule 21.06.2009
comment
Они говорят, что это потому, что Set является контекстным ключевым словом пары get/set, но разве это не набор в нижнем регистре? - person ilya n.; 21.06.2009
comment
Upvote - ссылка на блог команды BCL была бы моим ответом, но я только что увидел вопрос, и вы уже ответили на него. - person RichardOD; 21.06.2009
comment
Мне лично нравится, когда он называется Set<T>, оставляя детали реализации (хэш). - person nawfal; 25.05.2014
comment
Ну, есть Set<T>class, который является внутренним . Но он работает как HashSet<T>. - person Tim Schmelter; 03.07.2017

Единственной причиной этого кажется отсутствие ресурсов для идеальной реализации этого в .NET 3.5.

.NET 4.0 будет включать ISet, а также его новая реализация в дополнение к HashSet - SortedSet. Ознакомьтесь с предоставленными ссылками на библиотеку MSDN — они уже доступны в .NET 4.0 beta1.

person Alex Yakunin    schedule 21.06.2009
comment
Удивительно, как вы это нашли, спасибо! Хотел бы я принять два ответа. - person ilya n.; 21.06.2009

set — это ключевое слово языка C#, которое используется с версии 1.0. Is используется для определения части свойства, присваивающей значение (а get используется для реализации части свойства, считывающей значение). В этом контексте вы должны понимать слово «установить» как глагол, как при установке значения.

HashSet<T> — это конкретная реализация математической концепции множества. Впервые он был представлен в .NET 3.5. Этот пост в блоге команды BCL объясняет больше причин, лежащих в его основе, а также некоторые подсказки, почему имя HashSet<T>, а не просто Set<T>: http://blogs.msdn.com/bclteam/archive/2006/11/09/introduction-hashset-t-kim-hamilton.aspx.

В случае HashSet<T> вы должны понимать слово "набор" как существительное.

person Mark Seemann    schedule 21.06.2009
comment
Я не могу разгадать подсказки :) Лучшее, что я могу понять, это то, что Set каким-то образом зарезервирован из-за VB. - person ilya n.; 21.06.2009
comment
Потому что я знаю о set как о глаголе, но я думаю, что C# чувствителен к регистру, так зачем его смешивать с Set? - person ilya n.; 21.06.2009
comment
Set действительно является ключевым словом в VB.NET. Хотя C# чувствителен к регистру, CLS — нет, поэтому существует опасность, что в языке, не чувствительном к регистру (таком как VB.NET), возникнут проблемы с различением ключевого слова и типа. Даже если компилятор сможет это понять, разработчики могут запутаться. Таким образом, в Руководстве по проектированию фреймворка рекомендуется избегать определенных ключевых слов в качестве имен типов. HashSet<T> был разработан для использования с любым языком на основе .NET, а не только с C#. - person Mark Seemann; 21.06.2009

Set — зарезервированное ключевое слово в VB.NET (эквивалентно set в C#). VB.NET может использовать классы/методы/и т. д. с тем же именем, что и ключевые слова, но они должны быть написаны между квадратными скобками, что некрасиво:

Imports Wintellect.PowerCollections 'PowerCollections contains a class called Set'
Public Class Test
    Private _myValue As Integer  

    Public Property MyValue() As Integer
        Get
            Return _myValue
        End Get
        Set ' Set as keyword'
            _myValue = value
        End Set
    End Property

    Public Function X As [Set](Of Integer)
        Dim a As New [Set](Of Integer) ' Set as class'
        Return a
    End Function

End Class
person ggf31416    schedule 21.06.2009
comment
Нет, извините, я не понимаю. Как связаны C# и VB/.NET? - person ilya n.; 21.06.2009
comment
VB.NET и C# — основные языки .NET, они почти эквивалентны по возможностям, компилируются почти в один и тот же IL, и Microsoft пообещала сделать их ближе в будущем. Сообщество VB.NET довольно велико, но вы не видите столько вопросов о VB.NET, потому что многие из них без проблем понимают C#. - person ggf31416; 21.06.2009

А, теперь я понял ваш вопрос
Не уверен, что могу на 100% увидеть необходимость в ISet<T>.
Думаю, вопрос в том, какое поведение вы считаете важным для набора?
Так ли это? Добавить, Удалить, Содержит и т. д. Если это так, то ICollection<T> уже предоставляет для этого интерфейс.
Если это такие операции над наборами, как объединение, пересечение и т. д., то это то, что вы считаете достаточно общим, чтобы абстрагироваться от стиля контракта. правоприменение?

Я должен сказать, что не знаю правильного ответа на этот вопрос - я думаю, что он открыт для обсуждения, и я подозреваю, что команда BCL может в конечном итоге добавить что-то подобное в будущую версию, но это зависит от них. Лично я не считаю это огромной недостающей частью функциональности.

Исходное сообщение

В BCL вообще нет коллекции Set, по крайней мере, насколько мне известно.
Существует несколько сторонних библиотек Set, таких как Iesi.Collections
HashSet<T> был введен в .NET 3.5 для создания коллекции быстрого набора, т. е. там, где вам нужна коллекция без дубликатов. Он также имеет типичные операции с множествами, такие как объединение и соединение. Просмотрите эту ссылку от команды BCL на HashSet

Обычно вы использовали его там, где раньше вам приходилось использовать List<T> и проверять наличие дубликатов при добавлении.
Добавление элементов в HashSet<T> также может быть значительно быстрее, чем список

Некоторые дополнительные подробности:
Еще одна приятная особенность HashSet заключается в том, что он не генерирует исключение, если вы пытаетесь добавить дубликат, он просто не добавляет повторяющуюся запись, что избавляет вас от необходимости размещать множество блоков try.catch. каждое добавление - приятно :)

person zebrabox    schedule 21.06.2009
comment
Хорошо, но почему бы не иметь интерфейс ISet со всеми этими свойствами и HashSet, который его реализует? Вот как работает словарь. - person ilya n.; 21.06.2009

Я почти уверен, что в BCL нет класса Set<T>, по крайней мере, в .NET 3.5 (и, похоже, не в .NET 4.0). В любом случае, что вы ожидаете от такого класса?

HashSet<T> сама по себе является обычной структурой набора данных, которая использует хеш-коды (метод GetHashCode объекта) для сравнения элементов. Это просто эффективный способ реализации заданного типа. (Другие методы проверки равенства, вероятно, будут иметь более низкую производительность.)

person Noldorin    schedule 21.06.2009
comment
HashSet использует GetHashCode для поиска элементов внутри своих сегментов. Он по-прежнему сравнивает элементы, используя Equals, в случае, если два элемента имеют одинаковый HashCode и попадают в одно и то же ведро. - person Noam Gal; 21.06.2009
comment
@Noam: Действительно, это так. Моя точка зрения заключалась в том, что GetHashCode является основным методом сравнения. Equals в значительной степени используется в качестве резервной копии. - person Noldorin; 21.06.2009