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.
También tenga en cuenta que debe escribir 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).
tux21b
55
La solución es simple, eso es cierto. ¿Pero qué se necesita para agregar una funcionalidad tan básica al tiempo de ejecución? No he encontrado tales problemas en Go repo en github. Eso es triste y extraño.
Igor Petrov
1
¿Cómo se map[string] boolcompara con map[string] struct{}. map[string] struct{}parece un truco especialmente inicializando una estructura vacíastruct {}{}
vadasambar
@IgorPetrov estuvo de acuerdo, me sorprende que una característica tan básica no esté en el tiempo de ejecución.
jcollum
180
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 {returntrue}}returnfalse}
Puede usar un mapa si esa búsqueda es una parte importante de su código, pero los mapas también han costado.
En realidad, no es trivial, porque tiene que escribir uno para cada tipo que usa, y debido a que no hay sobrecarga, debe nombrar cada función de manera diferente, como en C. append () puede funcionar genéricamente porque tiene soporte especial de tiempo de ejecución. Un contenido genérico sería útil por la misma razón, pero en realidad la solución genérica es solo el soporte genérico en el idioma.
Eloff
15
@Eloffinterface{}
Alex Lockwood
2
@Alex Lockwood, ¿esto realmente funcionará con interfaces?
Ory Band
101
trivial == 7 líneas de código incluyendo 1 bucle 1 rama si declaración y 1 comparación? Creo que me estoy perdiendo algo aquí ...
tothemario
3
Pero, ¿por qué no agregar estos en Go Core?
Luna Lovegood
16
Si el segmento está ordenado, hay una búsqueda binaria implementada en el sortpaquete .
En lugar de usar a slice, mappuede 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))}
En su forma actual, este código no ofrece ningún beneficio, ya que no tiene sentido construir un mapa a partir de un segmento si solo lo va a usar una vez. - Para ser útil, este código debería proporcionar una función sliceToMapque haga toda la preparación. Después de eso, consultar el mapa es trivial y eficiente.
Roland Illig
9
El paquete de clasificación proporciona los bloques de construcción si su segmento está ordenado o si está dispuesto a ordenarlo.
SearchStringpromete 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.
En términos de tiempo, la búsqueda regular es O(n)y esta solución lo hace O(n*log(n)).
plesiv
@plesiv es una búsqueda binaria, AFAICS. ¿No sería eso O (log n)?
Henrik Aasted Sørensen
sí, binary-search y la función containsson O(log(n)), pero el enfoque general se O(n*log(n))debe al tipo.
plesiv
3
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.Interfaceif arrV.Index(i).Interface()== elem {returntrue}}}returnfalse}
Claro que puedes usar el paquete reflect, pero solo porque puedas, no significa que debas hacerlo. La reflexión es muy cara.
Justin Ohms
3
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 Foostruct{Field1stringField2int}
func Test(m Foo)bool{var allItems []Fooreturn deriveContainsFoo(allItems, m)}
Para generar el método deriveContainsFoo:
Instalar goderive con go get -u github.com/awalterschulze/goderive
Ejecutar goderive ./...en su carpeta de espacio de trabajo
Este método se generará para deriveContains:
func deriveContainsFoo(list []Foo, item Foo)bool{for _, v := range list {if v == item {returntrue}}returnfalse}
Goderive tiene soporte para otros métodos auxiliares útiles para aplicar un estilo de programación funcional en go.
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 Identifiableinterface{GetIdentity()string}
func IsIdentical(thisIdentifiable, that Identifiable)bool{return(&this==&that)||(this.GetIdentity()== that.GetIdentity())}
func contains(s []Identifiable, e Identifiable)bool{for _, a := range s {ifIsIdentical(a,e){returntrue}}returnfalse}
"no es más de lo que tendrías que hacer en otros lenguajes" no es realmente cierto, por ejemplo, en C # Contains()está implementado List<T>, por lo que solo tienes que implementarlo Equals()para ese trabajo.
George
1
Creé un punto de referencia muy simple con las soluciones de estas respuestas.
Lo pensé pero no es tan representativo debido al hecho de que mi máquina no es tan potente.
F. Norbert
-1
El estilo de ir:
func Contains(n int, match func(i int)bool)bool{for i :=0; i < n; i++{if match(i){returntrue}}returnfalse}
s :=[]string{"a","b","c","o"}// test if s contains "o"
ok :=Contains(len(s), func(i int)bool{return s[i]=="o"})
Esto no responde a la pregunta, ni proporciona información adicional.
Croolman
-1
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.
No funcionará para situaciones en las que los elementos tienen texto similar pero no exactamente el mismoexSlice := ["yes and no", "maybe", "maybe another"]
Raees Iqbal
Este es un enfoque bastante agradable para lograr una solución rápida y sucia. Solo necesita requerir un delimitador inequívoco (podría ser una coma) y hacer el trabajo adicional para poner entre corchetes ambas cadenas: ","+strings.Join(exSlice,",")+","y",maybe,"
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 unmap[string]struct{}
por ejemplo. Usar unstruct{}
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.fuente
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 conmap[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:
Puede usar un mapa si esa búsqueda es una parte importante de su código, pero los mapas también han costado.
fuente
interface{}
Si el segmento está ordenado, hay una búsqueda binaria implementada en el
sort
paquete .fuente
En lugar de usar a
slice
,map
puede ser una mejor solución.ejemplo simple:
http://play.golang.org/p/CEG6cu4JTf
fuente
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.
SearchString
promete regresarthe 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.fuente
O(n)
y esta solución lo haceO(n*log(n))
.contains
sonO(log(n))
, pero el enfoque general seO(n*log(n))
debe al tipo.Puede utilizar la reflejan paquete para iterar sobre una interfaz cuyo tipo concreto es una rebanada:
https://play.golang.org/p/jL5UD7yCNq
fuente
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;
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:
Goderive tiene soporte para otros métodos auxiliares útiles para aplicar un estilo de programación funcional en go.
fuente
fuente
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.
fuente
Contains()
está implementadoList<T>
, por lo que solo tienes que implementarloEquals()
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.
fuente
El estilo de ir:
fuente
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
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.
fuente
exSlice := ["yes and no", "maybe", "maybe another"]
","+strings.Join(exSlice,",")+","
y",maybe,"