golang, почему у нас нет заданной структуры данных [закрыто]

130

Я пытаюсь выполнить упражнение №1.4 "Язык программирования Go", которое требует от меня набора. Я могу создать наборный тип, но почему в языке нет его? go, пришедший из Google, где также возникла гуава, почему разработчики языка не решили добавить поддержку фундаментальных структур данных? зачем заставлять пользователей создавать свои собственные реализации для чего-то столь простого, как набор?

anjanb
источник
11
хммм. интересно, почему отрицательные голоса? Я пришел из мира java, где у нас был набор почти с самого начала, даже без дженериков. Итак, я нахожу такое поведение
немного

Ответы:

83

Отчасти потому, что в Go нет универсальных шаблонов (поэтому вам понадобится один набор-тип для каждого типа или прибегать к отражению, что довольно неэффективно).

Отчасти потому, что если все, что вам нужно, это «добавить / удалить отдельные элементы в набор» и «относительно компактно», вы можете получить немного этого, просто используя map[yourtype]bool(и устанавливая значение trueдля любого элемента в наборе ) или, для большей экономии места, вы можете использовать пустую структуру в качестве значения и использовать _, present = the_setoid[key]для проверки наличия.

Vatine
источник
1
Кроме того, похоже, в духе Go просто записать это в своем собственном коде, либо «встраивая» набор в другой код, либо определяя свой собственный тип набора, когда это необходимо. В любом случае, использование, например, std :: set <T> в C ++ всегда происходит как часть реализации функции или реализации какой-либо другой структуры данных. Поэтому просто реализуйте эту другую структуру данных напрямую, используя карты, срезы и любые другие строительные блоки, которые вам нужны, но без какого-либо встроенного набора. В любом случае, при каждом использовании набора он будет использоваться немного по-своему :)
Бьярке Эберт,
1
Но обычно вам не нужен сам по себе set <Foo>, вы используете set <Foo> как часть реализации чего-то большего. Я видел тонны кода, где то, что вам нужно сделать, чтобы включить «многоразовый» компонент, намного хуже, чем просто избежать необходимости. Итак, у нас есть set <Foo>, этой функции там нужен set <Bar>, ой, есть ли у нас еще ковариация, или как насчет создания WrapperFactory, чтобы эта вещь выглядела так, как эта, и т. Д. Может быть, эта другая функция на самом деле просто нужен интерфейс, который может проверять членство, поэтому не отправляйте ему set <Foo>.
Бьярке Эберт
42
Итак, если у него нет универсальных шаблонов, как вообще реализуется «универсальная» карта?
Фермин Сильва,
26
Обратите внимание, что если вы хотите сохранить байты, вы можете использовать map[T]struct{}вместо map[T]bool.
всплытие
4
Посмотрите emersion.fr/blog/2017/sets-in-go
emersion
69

Одна из причин заключается в том, что создать набор из карты легко:

s := map[int]bool{5: true, 2: true}
_, ok := s[6] // check for existence
s[8] = true // add element 
delete(s, 2) // remove element

союз

s_union := map[int]bool{}
for k, _ := range s1{
    s_union[k] = true
}
for k, _ := range s2{
    s_union[k] = true
}

пересечение

s_intersection := map[int]bool{}
for k,_ := range s1 { 
  if s2[k] {
    s_intersection[k] = true
  }
}

Реализовать все остальные операции над наборами не так уж и сложно.

Сальвадор Дали
источник
10
Проверка существования - это просто индексирование карты. Поскольку, если его нет, нулевое значение (которое есть false) правильно скажет об этом. Не нужна идиома-запятая для тестирования.
icza 01
2
Реализация пересечения выглядит так для отличия.
musiphil
1
@Kittsil, спасибо. Обновлено.
Сальвадор Дали
34
Более оптимально использовать map[int]struct{}вместо bool, потому что пустая структура занимает в памяти 0 байтов. Я недавно написал суть этого gist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80
Б.Г. Адриан
13
Это не так просто. В наши дни мне кажется нелепым просто писать этот код везде, где вам нужно использовать Set. Поддержка коллекций должна осуществляться на любом языке. Думаю, лучший ответ состоит в том, что Go еще не так зрел. Я уверен, что в ближайшее время появятся библиотеки для этого.
Stef
5

Как писал Ватин: поскольку в go отсутствуют универсальные шаблоны, он должен быть частью языка, а не стандартной библиотекой. Для этого вам придется засорять язык набором ключевых слов, объединением, пересечением, различием, подмножеством ...

Другая причина в том, что совсем не ясно, какова «правильная» реализация набора:

  1. Есть функциональный подход:

    func IsInEvenNumbers(n int) bool {
        if n % 2 == 0 {
            return true
        }
       return false
    }

Это набор всех четных int. Он имеет очень эффективный поиск и объединение, пересечение, различие и подмножество, которые можно легко выполнить с помощью функциональной композиции.

  1. Или вы используете подход, подобный тому, как это показал Дали.

У карты нет такой проблемы, поскольку вы храните что-то, связанное со значением.

0x434D53
источник
2
Для обработки встроенных наборов Паскаль перегружает кучу бинарных (с двумя аргументами) операторов: +для объединения, -для разности, *для пересечения, <=для подмножества, >=для надмножества, =для равенства, <>для неравенства и inдля членства. Таким образом, в Go это будет только одно новое ключевое слово - in. С другой стороны, встроенные наборы Паскаля работают только с «порядковыми числами», то есть с любым типом, в основе которого лежит представление целочисленного значения некоторого размера.
kostix 01
9
Тот факт, что существует несколько способов реализовать набор, не помешал многим другим языкам предоставить их.
augurar
@kostix: Go может даже использовать синтаксис s[key](как если бы sбыл a map[T]bool) вместо key in s.
musiphil
2
Есть ли причина не просто вернуться n % 2 == 0?
Жоао Андраде
4

Другая возможность - использовать наборы битов, для которых существует хотя бы один пакет, или вы можете использовать встроенный большой пакет. В этом случае в основном вам нужно определить способ преобразования вашего объекта в индекс.

Уилл Фицджеральд
источник
1
Я должен отметить, что я написал исходную версию пакета битов, упомянутого выше.
Уилл Фицджеральд