Réponses:
Mostafa a déjà souligné qu'une telle méthode est triviale à écrire, et mkb vous a donné un indice pour utiliser la recherche binaire à partir du package de tri. Mais si vous allez faire beaucoup de ces contrôles contient, vous pouvez également envisager d'utiliser une carte à la place.
Il est trivial de vérifier si une clé de carte spécifique existe en utilisant l' value, ok := yourmap[key]
idiome. Puisque vous n'êtes pas intéressé par la valeur, vous pouvez également créer un map[string]struct{}
exemple. L'utilisation d'un espace vide struct{}
ici a l'avantage de ne pas nécessiter d'espace supplémentaire et 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 décors du monde Go.
struct{}{}
pour obtenir la valeur de la structure vide afin de pouvoir la transmettre à votre carte lorsque vous souhaitez ajouter un élément. Essayez-le et si vous rencontrez des problèmes, n'hésitez pas à demander. Vous pouvez également utiliser la solution de Mostafa si cela vous est plus facile à comprendre (sauf si vous avez d'énormes quantités de données).
map[string] bool
compare-t-il à map[string] struct{}
. map[string] struct{}
semble être un hack, surtout en initialisant une structure videstruct {}{}
Non, une telle méthode n'existe pas, mais est banale à é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 est une partie importante de votre code, mais les cartes ont également un coût.
interface{}
Si la tranche est triée, une recherche binaire est implémentée dans le sort
package .
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))
}
sliceToMap
qui fait toute la préparation. Après cela, interroger la carte est trivial et efficace.
Le package de tri fournit les blocs de construction si votre tranche est triée ou si vous souhaitez la trier.
input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)
fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow")) // false
...
func contains(s []string, searchterm string) bool {
i := sort.SearchStrings(s, searchterm)
return i < len(s) && s[i] == searchterm
}
SearchString
promet de revenir the index to insert x if x is not present (it could be len(a))
, donc une vérification de cela révèle si la chaîne contient la tranche triée.
O(n)
et cette solution le fait O(n*log(n))
.
contains
sont O(log(n))
, mais l'approche globale est O(n*log(n))
due au tri.
Vous pouvez utiliser le package de réflexion 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
}
S'il n'est pas possible d'utiliser une carte pour trouver des éléments en fonction d'une clé, vous pouvez envisager l' outil goderive . Goderive génère une implémentation spécifique au type d'une méthode contains, 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 travailCette 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 prend en charge de nombreuses autres méthodes d'aide utiles pour appliquer un style de programmation fonctionnel en cours.
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
}
Pas sûr que les génériques soient nécessaires ici. Vous avez juste besoin d'un contrat pour votre comportement souhaité. Faire 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 les collections, en remplaçant Equals () et GetHashCode () par exemple.
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
}
Contains()
est implémenté List<T>
, vous n'avez donc qu'à l'implémenter Equals()
pour ce travail.
J'ai créé un benchmark très simple avec les solutions de ces réponses.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
Ce n'est pas une vraie référence car au départ, je n'ai pas inséré trop d'éléments mais n'hésitez pas à le fork et à le changer.
Le style go:
func Contains(n int, match func(i int) bool) bool {
for i := 0; i < n; i++ {
if match(i) {
return true
}
}
return false
}
s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
return s[i] == "o"
})
Cela peut être considéré comme un peu «hacky» mais en fonction de la taille et du contenu de la tranche, vous pouvez joindre la tranche ensemble et faire une recherche de chaîne.
Par exemple, vous avez une tranche contenant des valeurs de mot unique (par exemple "oui", "non", "peut-être"). Ces résultats sont ajoutés à une tranche. Si vous souhaitez vérifier si cette tranche contient des résultats "peut-être", vous pouvez utiliser
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
Son adéquation dépend en réalité de la taille de la tranche et de la longueur de ses membres. Il peut y avoir des problèmes de performances ou d'adéquation pour les grandes tranches ou les valeurs longues, mais pour les tranches plus petites de taille finie et de valeurs simples, il s'agit d'une doublure valide pour obtenir le résultat souhaité.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
",maybe,"