Existe-t-il une méthode similaire à une méthode slice.contains(object)
dans Go sans avoir à effectuer une recherche dans chaque élément d'une tranche?
Mostafa a déjà fait remarquer qu'une telle méthode est facile à écrire et mkb vous a donné un indice pour utiliser la recherche binaire du paquet de tri. Mais si vous allez effectuer beaucoup de vérifications de ce type, vous pouvez également utiliser une carte.
Il est facile de vérifier si une clé de carte spécifique existe en utilisant l'idiome value, ok := yourmap[key]
. Puisque la valeur ne vous intéresse pas, vous pouvez également créer un map[string]struct{}
par exemple. L'utilisation d'un struct{}
vide a l'avantage de ne pas nécessiter d'espace supplémentaire et que le type de carte interne de Go est optimisé pour ce type de valeurs. Par conséquent, map[string] struct{}
est un choix populaire pour les ensembles du monde de Go.
Non, une telle méthode n'existe pas, mais il est facile d'écrire:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Vous pouvez utiliser une carte si cette recherche constitue une partie importante de votre code, mais les cartes ont également un coût.
Si la tranche est triée, une recherche binaire est implémentée dans le package sort
.
Au lieu d'utiliser un slice
, map
peut être une meilleure solution.
exemple simple:
package main
import "fmt"
func contains(slice []string, item string) bool {
set := make(map[string]struct{}, len(slice))
for _, s := range slice {
set[s] = struct{}{}
}
_, ok := set[item]
return ok
}
func main() {
s := []string{"a", "b"}
s1 := "a"
fmt.Println(contains(s, s1))
}
Vous pouvez utiliser le package reflect pour parcourir une interface dont le type concret est une tranche:
func HasElem(s interface{}, elem interface{}) bool {
arrV := reflect.ValueOf(s)
if arrV.Kind() == reflect.Slice {
for i := 0; i < arrV.Len(); i++ {
// XXX - panics if slice element points to an unexported struct field
// see https://golang.org/pkg/reflect/#Value.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
Pas sûr que les génériques soient nécessaires ici. Vous avez juste besoin d'un contrat pour votre comportement souhaité. Ce qui suit n’est rien de plus que ce que vous auriez à faire dans d’autres langues si vous vouliez que vos propres objets se comportent dans des collections, en surchargeant par exemple Equals () et GetHashCode ().
type Identifiable interface{
GetIdentity() string
}
func IsIdentical(this Identifiable, that Identifiable) bool{
return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}
func contains(s []Identifiable, e Identifiable) bool {
for _, a := range s {
if IsIdentical(a,e) {
return true
}
}
return false
}
S'il n'est pas possible d'utiliser une carte pour rechercher des éléments en fonction d'une clé, vous pouvez utiliser l'outil goderive . Goderive génère une implémentation spécifique à un type de la méthode contient, rendant votre code à la fois lisible et efficace.
Exemple;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Pour générer la méthode deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
dans votre dossier d’espace de travail.Cette méthode sera générée pour deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive supporte pas mal d’autres méthodes utiles pour appliquer un style de programmation fonctionnel à la volée.
func Contain(target interface{}, list interface{}) (bool, int) {
if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
listvalue := reflect.ValueOf(list)
for i := 0; i < listvalue.Len(); i++ {
if target == listvalue.Index(i).Interface() {
return true, i
}
}
}
if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
}
return false, -1
}