golang, perché non abbiamo una struttura dati impostata [chiusa]


130

Sto cercando di risolvere l'esercizio # 1.4 "Il linguaggio di programmazione go" che richiede di avere un set. Posso creare un tipo di set ma perché la lingua non ne ha uno? vai, provenendo da google, dove ha avuto origine anche guava, perché i progettisti del linguaggio non hanno optato per l'aggiunta del supporto per le strutture dati fondamentali? perché costringere i tuoi utenti a creare le proprie implementazioni per qualcosa di così semplice come un set?


11
hmmm. chiedendosi perché i voti negativi? Vengo dal mondo Java dove avevamo un set quasi dall'inizio, anche senza generici. Quindi, trovo questo comportamento un
po

Risposte:


83

In parte, perché Go non ha generici (quindi avresti bisogno di un tipo di set per ogni tipo, o ripiegare sulla riflessione, che è piuttosto inefficiente).

In parte, perché se tutto ciò di cui hai bisogno è "aggiungere / rimuovere singoli elementi a un insieme" e "relativamente efficiente in termini di spazio", puoi ottenerne una buona parte semplicemente usando a map[yourtype]bool(e impostare il valore su trueper qualsiasi elemento dell'insieme ) oppure, per una maggiore efficienza dello spazio, è possibile utilizzare una struttura vuota come valore e utilizzare _, present = the_setoid[key]per verificare la presenza.


1
Inoltre, sembra essere nello spirito di Go semplicemente scriverlo nel proprio codice, "incorporando" il set in un altro codice, o definire il proprio tipo di set quando necessario. Ad ogni modo, l'utilizzo ad esempio di std :: set <T> in C ++ avviene sempre come parte dell'implementazione di una funzione o dell'implementazione di qualche altra struttura di dati. Pertanto, implementa direttamente l'altra struttura dati utilizzando mappe e sezioni e qualsiasi altro blocco di costruzione di cui hai bisogno, ma senza alcun set integrato. Ogni utilizzo di un set lo utilizzerà comunque in modo leggermente diverso :)
Bjarke Ebert

1
Ma di solito non hai davvero bisogno di un set <Foo> da solo, usi un set <Foo> come parte dell'implementazione di qualcosa di più grande. Ho visto tonnellate di codice in cui le cose che devi fare per includere un componente "riutilizzabile" sono molto peggiori del semplice evitarne la necessità. Quindi qui abbiamo un insieme <Foo>, quella funzione laggiù ha bisogno di un insieme <Bar>, oops, abbiamo ancora la covarianza, o che ne dici di creare una WrapperFactory per far sembrare questa cosa come questa cosa, ecc. Forse quell'altra funzione ha solo bisogno di un'interfaccia che possa controllare l'appartenenza, quindi non inviare un set <Foo>.
Bjarke Ebert

42
Quindi, se non ha generici, come viene implementata la mappa "generica"?
Fermin Silva

26
Nota che se vuoi salvare i byte, puoi usare map[T]struct{}invece di map[T]bool.
emersione


69

Uno dei motivi è che è facile creare un set dalla mappa:

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

Unione

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

Intersezione

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

Non è poi così difficile implementare tutte le altre operazioni sui set.


10
Verificare l'esistenza è semplicemente indicizzare la mappa. Poiché se non è in esso, il valore zero (che è false) lo dirà correttamente. Non è necessario l'idioma virgola-ok per i test.
icza

2
L'implementazione per l'intersezione sembra quella per la differenza.
musiphil

1
@Kittsil grazie. Aggiornato.
Salvador Dali

34
È più ottimale da usare map[int]struct{}invece di bool, perché una struttura vuota occupa 0 byte nella memoria. Recentemente ho scritto una sintesi
BG Adrian

13
Non è così facile. Il solo fatto di dover scrivere quel codice ovunque sia necessario utilizzare un Set mi sembra ridicolo di questi tempi. Il supporto per le raccolte dovrebbe essere fornito da qualsiasi lingua. Penso che una risposta migliore sia che Go non è ancora maturo. Sono sicuro che ci saranno biblioteche per occuparsene abbastanza presto.
Stef

5

Come ha scritto Vatine: poiché go manca di generici, dovrebbe far parte del linguaggio e non della libreria standard. Per questo dovresti quindi inquinare la lingua con set di parole chiave, unione, intersezione, differenza, sottoinsieme ...

L'altro motivo è che non è affatto chiaro quale sia l'implementazione "giusta" di un set:

  1. C'è un approccio funzionale:

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

Questo è un insieme di tutti gli int pari. Ha una ricerca molto efficiente e l'unione, l'intersezione, la differenza e il sottoinsieme possono essere facilmente fatti dalla composizione funzionale.

  1. Oppure fai un approccio simile a quello mostrato da Dalì.

Una mappa non presenta questo problema, poiché memorizzi qualcosa associato al valore.


2
Per gestire gli insiemi incorporati, Pascal sovraccarica un gruppo di operatori binari (a due argomenti): +per unione, -per differenza, *per intersezione, <=per sottoinsieme, >=per superserie, =per uguaglianza, <>per disuguaglianza e inper appartenenza. Quindi in Go, sarebbe solo una singola nuova parola chiave - in. D'altra parte, gli insiemi incorporati di Pascal funzionano solo su "ordinali", cioè qualsiasi tipo che abbia una rappresentazione sottostante di un valore intero di una certa dimensione.
kostix

9
Il fatto che ci siano più modi per implementare un set non ha impedito a molti altri linguaggi di fornirli.
augurar

@kostix: Go potrebbe anche usare la sintassi s[key](come se sfosse a map[T]bool) invece di key in s.
musiphil

2
Qualche motivo per non tornare semplicemente n % 2 == 0?
João Andrade

4

Un'altra possibilità è usare set di bit, per i quali esiste almeno un pacchetto oppure puoi usare il pacchetto grande incorporato . In questo caso, fondamentalmente devi definire un modo per convertire il tuo oggetto in un indice.


1
Devo notare che ho scritto la versione originale del pacchetto bitset a cui si fa riferimento sopra.
Will Fitzgerald
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.