Respuestas:
Mostafa ya ha señalado que dicho método es trivial de escribir, y mkb le dio una pista para usar la búsqueda binaria del paquete de clasificación. Pero si va a hacer una gran cantidad de tales controles, también puede considerar usar un mapa.
Es trivial verificar si existe una clave de mapa específica usando el value, ok := yourmap[key]
idioma. Como no está interesado en el valor, también puede crear un map[string]struct{}
por ejemplo. Usar un struct{}
espacio vacío aquí tiene la ventaja de que no requiere espacio adicional y el tipo de mapa interno de Go está optimizado para ese tipo de valores. Por lo tanto, map[string] struct{}
es una opción popular para sets en el mundo Go.
struct{}{}
para obtener el valor de la estructura vacía para poder pasarla a su mapa cuando desee agregar un elemento. Simplemente pruébelo y, si encuentra algún problema, no dude en preguntar. También puede usar la solución de Mostafa si le resulta más fácil de entender (a menos que tenga grandes cantidades de datos).
map[string] bool
compara con map[string] struct{}
. map[string] struct{}
parece un truco especialmente inicializando una estructura vacíastruct {}{}
No, dicho método no existe, pero es trivial de escribir:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
Puede usar un mapa si esa búsqueda es una parte importante de su código, pero los mapas también han costado.
interface{}
Si el segmento está ordenado, hay una búsqueda binaria implementada en el sort
paquete .
En lugar de usar a slice
, map
puede ser una mejor solución.
ejemplo 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
que haga toda la preparación. Después de eso, consultar el mapa es trivial y eficiente.
El paquete de clasificación proporciona los bloques de construcción si su segmento está ordenado o si está dispuesto a ordenarlo.
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
promete regresar the index to insert x if x is not present (it could be len(a))
, por lo que una comprobación de eso revela si la cadena está contenida en el segmento ordenado.
O(n)
y esta solución lo hace O(n*log(n))
.
contains
son O(log(n))
, pero el enfoque general se O(n*log(n))
debe al tipo.
Puede utilizar la reflejan paquete para iterar sobre una interfaz cuyo tipo concreto es una rebanada:
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
}
Si no es factible utilizar un mapa para buscar elementos basados en una clave, puede considerar la herramienta de guía . Goderive genera una implementación específica de tipo de un método contiene, haciendo que su código sea legible y eficiente.
Ejemplo;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
Para generar el método deriveContainsFoo:
go get -u github.com/awalterschulze/goderive
goderive ./...
en su carpeta de espacio de trabajoEste método se generará para deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive tiene soporte para otros métodos auxiliares útiles para aplicar un estilo de programación funcional en go.
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
}
No estoy seguro de que se necesiten genéricos aquí. Solo necesita un contrato para su comportamiento deseado. Hacer lo siguiente no es más que lo que tendría que hacer en otros idiomas si quisiera que sus propios objetos se comporten en colecciones, anulando Equals () y GetHashCode (), por ejemplo.
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á implementado List<T>
, por lo que solo tienes que implementarlo Equals()
para ese trabajo.
Creé un punto de referencia muy simple con las soluciones de estas respuestas.
https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7
No es un punto de referencia real porque inicialmente, no he insertado demasiados elementos, pero no dude en bifurcarlo y cambiarlo.
El estilo de ir:
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"
})
Puede considerarse un poco 'hacky', pero dependiendo del tamaño y el contenido del segmento, puede unir el segmento y hacer una búsqueda de cadena.
Por ejemplo, tiene un segmento que contiene valores de una sola palabra (por ejemplo, "sí", "no", "tal vez"). Estos resultados se agregan a un segmento. Si desea verificar si esta porción contiene algún resultado "quizás", puede usar
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
Lo adecuado que esto sea realmente depende del tamaño del corte y la longitud de sus miembros. Puede haber problemas de rendimiento o idoneidad para cortes grandes o valores largos, pero para cortes más pequeños de tamaño finito y valores simples, es una línea válida para lograr el resultado deseado.
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
y",maybe,"