golang pourquoi n'avons-nous pas une structure de données définie [fermé]

130

J'essaye de résoudre l'exercice n ° 1.4 "Le langage de programmation go" qui me demande d'avoir un ensemble. Je peux créer un type d'ensemble, mais pourquoi la langue n'est-elle pas fournie avec un? go, venant de google, d'où la goyave est également originaire, pourquoi les concepteurs de langage n'ont-ils pas opté pour l'ajout de la prise en charge des structures de données fondamentales? pourquoi forcer vos utilisateurs à créer leurs propres implémentations pour quelque chose d'aussi basique qu'un ensemble?

Anjanb
la source
11
hmmm. vous vous demandez pourquoi les votes négatifs? Je viens du monde Java où nous avions un set presque dès le début, même sans génériques. Donc, je trouve ce comportement un peu bizarre
anjanb

Réponses:

83

En partie, parce que Go n'a pas de génériques (vous auriez donc besoin d'un type d'ensemble pour chaque type, ou recourez à la réflexion, ce qui est plutôt inefficace).

En partie, parce que si tout ce dont vous avez besoin est "d'ajouter / supprimer des éléments individuels à un ensemble" et "relativement peu encombrant", vous pouvez en obtenir une bonne partie simplement en utilisant a map[yourtype]bool(et en définissant la valeur sur truepour n'importe quel élément de l'ensemble ) ou, pour plus d'efficacité d'espace, vous pouvez utiliser une structure vide comme valeur et utiliser _, present = the_setoid[key]pour vérifier la présence.

Vatine
la source
1
De plus, il semble être dans l'esprit de Go de simplement l'écrire dans votre propre code, soit en "insérant" l'ensemble dans un autre code, soit en définissant votre propre type d'ensemble si nécessaire. Quoi qu'il en soit, l'utilisation par exemple d'un std :: set <T> en C ++ se produit toujours dans le cadre d'une implémentation de fonction ou d'une autre structure de données. Par conséquent, implémentez simplement cette autre structure de données directement à l'aide de cartes et de tranches et de tous les autres blocs de construction dont vous avez besoin, mais sans aucun ensemble intégré. Chaque utilisation d'un ensemble va de toute façon l'utiliser légèrement différemment :)
Bjarke Ebert
1
Mais en général, vous n'avez pas vraiment besoin d'un ensemble <Foo> seul, vous utilisez un ensemble <Foo> dans le cadre de l'implémentation de quelque chose de plus grand. J'ai vu des tonnes de code où les choses que vous devez faire pour inclure un composant "réutilisable" sont bien pires que simplement éviter le besoin. Nous avons donc ici un ensemble <Foo>, cette fonction là-bas a besoin d'un ensemble <Bar>, oups, avons-nous encore une covariance, ou que diriez-vous de créer une WrapperFactory pour que cette chose ressemble à cette chose, etc. Peut-être que cette autre fonction a vraiment juste besoin d'une interface qui peut vérifier l'appartenance, alors ne lui envoyez pas un ensemble <Foo>.
Bjarke Ebert
42
Donc, s'il n'y a pas de génériques, comment la carte «générique» est-elle implémentée?
Fermin Silva
26
Notez que si vous souhaitez enregistrer des octets, vous pouvez utiliser à la map[T]struct{}place de map[T]bool.
émersion
4
Jetez un œil sur emersion.fr/blog/2017/sets-in-go
emersion
69

L'une des raisons est qu'il est facile de créer un ensemble à partir d'une carte:

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

syndicat

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

Intersection

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

Il n'est pas vraiment si difficile de mettre en œuvre toutes les autres opérations d'ensemble.

Salvador Dali
la source
10
Vérifier l'existence consiste simplement à indexer la carte. Puisque si ce n'est pas dedans, la valeur zéro (qui est false) le dira correctement. Pas besoin de l'idiome virgule-ok pour tester.
icza
2
La mise en œuvre de l'intersection ressemble à celle de la différence.
musiphil
1
@Kittsil merci. Actualisé.
Salvador Dali
34
Il est plus optimal d'utiliser à la map[int]struct{}place de bool, car une structure vide occupe 0 octet dans la mémoire. J'ai récemment écrit un résumé
BG Adrian
13
Ce n'est pas si simple. Le simple fait d'avoir à écrire ce code partout où vous devez utiliser un Set me semble ridicule ces jours-ci. Le support des collections doit être fourni dans n'importe quelle langue. Pensez qu'une meilleure réponse est que Go n'est pas encore aussi mature. Je suis sûr qu'il y aura des bibliothèques pour couvrir cela assez tôt.
Stef
5

Comme l'écrivait Vatine: Puisque go manque de génériques, il devrait faire partie du langage et non de la bibliothèque standard. Pour cela il faudrait alors polluer la langue avec des mots-clés ensemble, union, intersection, différence, sous-ensemble ...

L'autre raison est qu'il n'est pas du tout clair quelle est la "bonne" implémentation d'un ensemble:

  1. Il existe une approche fonctionnelle:

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

Ceci est un ensemble de tous les entiers pairs. Il a une recherche très efficace et l'union, l'intersection, la différence et le sous-ensemble peuvent facilement être effectués par composition fonctionnelle.

  1. Ou vous faites une approche comme l'a montré Dali.

Une carte n'a pas ce problème, car vous stockez quelque chose associé à la valeur.

0x434D53
la source
2
Pour gérer les ensembles intégrés, Pascal surcharge un tas d'opérateurs binaires (à deux arguments): +pour l'union, -pour la différence, *pour l'intersection, <=pour un sous-ensemble, >=pour un sur-ensemble, =pour l'égalité, <>pour l'inégalité et inpour l'appartenance. Donc, dans Go, ce ne serait qu'un seul nouveau mot-clé - in. D'un autre côté, les ensembles intégrés de Pascal ne fonctionnent que sur les "ordinaux" - c'est-à-dire sur tout type qui a une représentation sous-jacente d'une valeur entière d'une certaine taille.
kostix
9
Le fait qu'il existe plusieurs façons d'implémenter un ensemble n'a pas empêché de nombreux autres langages de les fournir.
augurar
@kostix: Go pourrait même utiliser la syntaxe s[key](comme si sc'était a map[T]bool) au lieu de key in s.
musiphil
2
Une raison pour ne pas simplement revenir n % 2 == 0?
João Andrade
4

Une autre possibilité est d'utiliser des ensembles de bits, pour lesquels il existe au moins un package, ou vous pouvez utiliser le gros package intégré. Dans ce cas, vous devez essentiellement définir un moyen de convertir votre objet en index.

Will Fitzgerald
la source
1
Je dois noter que j'ai écrit la version originale du paquet bitset référencé ci-dessus.
Will Fitzgerald