Naprawdę lubię google golang, ale czy ktoś mógłby wyjaśnić, jakie są uzasadnienia dla implementatorów, którzy opuścili podstawową strukturę danych, taką jak zestawy ze standardowej biblioteki?
Naprawdę lubię google golang, ale czy ktoś mógłby wyjaśnić, jakie są uzasadnienia dla implementatorów, którzy opuścili podstawową strukturę danych, taką jak zestawy ze standardowej biblioteki?
Odpowiedzi:
Jednym z potencjalnych powodów tego pominięcia jest to, że bardzo łatwo jest modelować zestawy za pomocą mapy.
Szczerze mówiąc, myślę, że to trochę przeoczenie, ale patrząc na Perla, historia jest dokładnie taka sama. W Perlu dostajesz listy i tablice skrótów, w Go - tablice, plastry i mapy. W Perlu na ogół używasz tablicy mieszającej dla wszystkich problemów związanych z zestawem, to samo dotyczy Go.
Przykład
aby naśladować zbiór int w Go, definiujemy mapę:
set := make(map[int]bool)
Dodanie czegoś jest tak proste jak:
i := valueToAdd()
set[i] = true
Usunięcie czegoś jest po prostu
delete(set, i)
Potencjalną niezręczność tego konstruktu łatwo można oderwać:
type IntSet struct {
set map[int]bool
}
func (set *IntSet) Add(i int) bool {
_, found := set.set[i]
set.set[i] = true
return !found //False if it existed already
}
I usunąć i uzyskać można zdefiniować podobnie, mam pełną realizację tutaj . Główną wadą tutaj jest fakt, że go nie ma leków generycznych. Można to jednak zrobić interface{}
w takim przypadku, w którym uzyskałbyś wyniki get.
map[int]bool
jednego można użyć map[int]struct{}
zamiast tego. Wolę ostatni.
map[int]struct{}
.. struct{}
Zajmuje 0 bajtów.
map[int]struct{}
nie możesz zrobić, if mymap["key"] {
aby sprawdzić członkostwo. Google zaleca użyciebool
(wyszukaj „Zestaw można zaimplementować”).
Myślę, że ma to związek z golang
prostotą. set
y stają się bardzo użyteczne z difference
, intersection
, union
, issubset
, i tak dalej .. metod. Być może golang
zespół uznał, że to za dużo dla jednej struktury danych. Ale poza tym jest „głupi zestaw”, który tylko ma add
, contains
i remove
może być łatwo powielane z map
jak wyjaśnił @jozefg.
Poprzednia odpowiedź działa TYLKO JEŻELI klucz jest wbudowany. Aby uzupełnić poprzednią odpowiedź, oto sposób na zaimplementowanie zestawu, którego elementami są typy zdefiniowane przez użytkownika:
package math
// types
type IntPoint struct {
X, Y int
}
// set implementation for small number of items
type IntPointSet struct {
slice []IntPoint
}
// functions
func (p1 IntPoint) Equals(p2 IntPoint) bool {
return (p1.X == p2.X) && (p1.Y == p2.Y)
}
func (set *IntPointSet) Add(p IntPoint) {
if ! set.Contains(p) {
set.slice = append(set.slice, p)
}
}
func (set IntPointSet) Contains(p IntPoint) bool {
for _, v := range set.slice {
if v.Equals(p) {
return true
}
}
return false
}
func (set IntPointSet) NumElements() int {
return len(set.slice)
}
func NewIntPointSet() IntPointSet {
return IntPointSet{(make([]IntPoint, 0, 10))}
}
type mySet map[IntPoint]bool
działa doskonale. Wszystko, co jest wymagane od typu klucza używanego na mapie, to , że ma ==
i!=
. Równość typów struktur jest dobrze zdefiniowana, twoja Equals
metoda powinna być sprawiedliwa p1 == p2
.
Contains
zajmuje czas liniowy, a aMap[]
trwa cały czas, niezależnie od liczby członków. Lepsze rozwiązanie stworzyłoby wewnętrznie unikatowy klucz oparty na zawartości każdego elementu i wykorzystywałby zapytania w trybie ciągłym map
dostarczane przez ten typ. Istnieją nawet szybsze rozwiązania, które uwzględniają zachowanie pamięci podręcznej itp.