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]booljednego 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 golangprostotą. sety stają się bardzo użyteczne z difference, intersection, union, issubset, i tak dalej .. metod. Być może golangzespół uznał, że to za dużo dla jednej struktury danych. Ale poza tym jest „głupi zestaw”, który tylko ma add, containsi removemoże być łatwo powielane z mapjak 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]booldział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 Equalsmetoda powinna być sprawiedliwa p1 == p2.
Containszajmuje 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 mapdostarczane przez ten typ. Istnieją nawet szybsze rozwiązania, które uwzględniają zachowanie pamięci podręcznej itp.