Define a estrutura de dados em Golang

69

Eu realmente gosto do google golang, mas alguém poderia explicar qual é a lógica para os implementadores terem deixado de fora uma estrutura de dados básica, como conjuntos da biblioteca padrão?

cobie
fonte
8
A linguagem é realmente chamado Go, não golang
jozefg
92
Mas "golang" é mais pesquisável
Matt:
18
Muito mais pesquisável. O "go set" pesquisando no Google retorna imagens de uma placa de madeira com peças em preto e branco.
Doug Richardson

Respostas:

68

Um motivo potencial para essa omissão é que é realmente fácil modelar conjuntos com um mapa.

Para ser sincero, acho que também é um pouco de supervisão, no entanto, olhando para Perl, a história é exatamente a mesma. No Perl, você obtém listas e hashtables, no Go, obtém matrizes, fatias e mapas. No Perl, você geralmente usa uma hashtable para todo e qualquer problema relacionado a um conjunto, o mesmo se aplica ao Go.

Exemplo

para imitar um conjunto de entradas no Go, definimos um mapa:

set := make(map[int]bool)

Adicionar algo é tão fácil quanto:

i := valueToAdd()
set[i] = true

Excluir algo é apenas

delete(set, i)

E o constrangimento potencial dessa construção é facilmente abstraído:

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
}

E delete e get podem ser definidos da mesma forma, eu tenho a implementação completa aqui . A principal desvantagem aqui é o fato de que go não possui genéricos. No entanto, é possível fazer isso, interface{}caso em que você lançaria os resultados de get.

jozefg
fonte
3
Aqui está a minha versão ligeiramente revista com Contém e métodos Tamanho: play.golang.org/p/tDdutH672-
Rick-777
19
Em vez de map[int]boolum pode usar em seu map[int]struct{}lugar. Eu prefiro o último.
pepper_chico
20
map[int]struct{}.. O struct{}leva 0 bytes.
Boopathi Rajaa
2
github.com/fatih/set é uma implementação minha baseada em mapas e estruturas vazias. É thread-safe e tem uma API simples.
Fatih Arslan
6
Com map[int]struct{}você não pode fazer if mymap["key"] {para verificar a adesão. O Google recomenda o usobool (pesquise "Um conjunto pode ser implementado").
Timmmm
3

Eu acho que isso tem a ver com o golangfoco na simplicidade. sets se tornar realmente útil com difference, intersection, union, issubset, e assim por diante .. métodos. Talvez a golangequipe tenha achado que é demais para uma estrutura de dados. Mas caso contrário, um "conjunto de burro" que só tem add, containse removepode ser facilmente replicado com mapcomo explicado por @jozefg.

Akavall
fonte
discordo. um conjunto é usado principalmente para verificações de associação e semântica de uniqeness. uma implementação definida seria perfeitamente utilizável sem esses métodos. Dito isto, eles também são triviais para implementar.
Sedat Kapanoglu 17/08/19
2

A resposta anterior funciona apenas se a chave for do tipo interno. Para complementar a resposta anterior, aqui está uma maneira de implementar um conjunto cujos elementos são tipos definidos pelo usuário:

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))}
}
amahfouz
fonte
8
"funciona SOMENTE SE a chave for do tipo interno" está incorreta . type mySet map[IntPoint]boolfunciona perfeitamente bem. Tudo o que é necessário para o tipo de chave usado em um mapa é que ele possui ==e!= . A igualdade dos tipos de estrutura está bem definida, seu Equalsmétodo deve ser justo p1 == p2.
Dave C
11
É verdade que a igualdade para estruturas é bem definida, mas se a estrutura contiver mapas ou fatias como campos, eles serão comparados por referência e não por valor. Pode não ser o que você deseja.
Chaim-Leib Halbert
11
Eu levo um pouco de problema com esta solução, porque Containsleva tempo linear, enquanto aMap[]leva tempo constante, independentemente do número de membros. Uma solução melhor criaria internamente uma chave exclusiva com base no conteúdo de cada membro e alavancaria a consulta em tempo constante que o maptipo fornece. Soluções ainda mais rápidas que consideram o comportamento do cache etc. também existem.
Chaim-Leib Halbert