Sin iterar sobre toda la matriz, ¿cómo puedo verificar si estoy x
en la matriz usando Go? ¿El lenguaje tiene una construcción?
Como Python: if "x" in array: ...
Sin iterar sobre toda la matriz, ¿cómo puedo verificar si estoy x
en la matriz usando Go? ¿El lenguaje tiene una construcción?
Como Python: if "x" in array: ...
No hay un operador integrado para hacerlo en Go. Necesita iterar sobre la matriz. Puede escribir su propia función para hacerlo, así:
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
Si desea poder verificar la membresía sin iterar sobre la lista completa, debe usar un mapa en lugar de una matriz o un segmento, como este:
visitedURL := map[string]bool {
"http://www.google.com": true,
"https://paypal.com": true,
}
if visitedURL[thisSite] {
fmt.Println("Already been here.")
}
Otra solución si la lista contiene valores estáticos.
por ejemplo: verificar un valor válido de una lista de valores válidos:
func IsValidCategory(category string) bool {
switch category {
case
"auto",
"news",
"sport",
"music":
return true
}
return false
}
Esta es una cita del libro "Programación en marcha: creación de aplicaciones para el siglo XXI":
El uso de una búsqueda lineal simple como esta es la única opción para datos sin clasificar y está bien para pequeñas porciones (hasta cientos de elementos). Pero para los sectores más grandes, especialmente si estamos realizando búsquedas repetidas veces, la búsqueda lineal es muy ineficiente y, en promedio, requiere que se comparen la mitad de los elementos cada vez.
Go proporciona un método sort.Search () que utiliza el algoritmo de búsqueda binaria: esto requiere la comparación de solo elementos log2 (n) (donde n es el número de elementos) cada vez. Para poner esto en perspectiva, una búsqueda lineal de 1000000 artículos requiere 500000 comparaciones en promedio, con el peor de los casos de 1000000 comparaciones; Una búsqueda binaria necesita como máximo 20 comparaciones, incluso en el peor de los casos.
files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.Search(len(files),
func(i int) bool { return files[i] >= target })
if i < len(files) && files[i] == target {
fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}
n*log(n) + log(n)
, ya que son dos operaciones independientes consecuentes
El ejemplo anterior usando sort está cerca, pero en el caso de cadenas simplemente use SearchString:
files := []string{"Test.conf", "util.go", "Makefile", "misc.go", "main.go"}
target := "Makefile"
sort.Strings(files)
i := sort.SearchStrings(files, target)
if i < len(files) && files[i] == target {
fmt.Printf("found \"%s\" at files[%d]\n", files[i], i)
}
sort.SearchStrings
.
Simplemente tuve una pregunta similar y decidí probar algunas de las sugerencias en este hilo.
He comparado los mejores y peores escenarios de 3 tipos de búsqueda:
Aquí está el código de función:
func belongsToMap(lookup string) bool {
list := map[string]bool{
"900898296857": true,
"900898302052": true,
"900898296492": true,
"900898296850": true,
"900898296703": true,
"900898296633": true,
"900898296613": true,
"900898296615": true,
"900898296620": true,
"900898296636": true,
}
if _, ok := list[lookup]; ok {
return true
} else {
return false
}
}
func belongsToList(lookup string) bool {
list := []string{
"900898296857",
"900898302052",
"900898296492",
"900898296850",
"900898296703",
"900898296633",
"900898296613",
"900898296615",
"900898296620",
"900898296636",
}
for _, val := range list {
if val == lookup {
return true
}
}
return false
}
func belongsToSwitch(lookup string) bool {
switch lookup {
case
"900898296857",
"900898302052",
"900898296492",
"900898296850",
"900898296703",
"900898296633",
"900898296613",
"900898296615",
"900898296620",
"900898296636":
return true
}
return false
}
los mejores escenarios seleccionan el primer elemento de las listas, los peores casos usan valores no existentes.
aquí están los resultados:
BenchmarkBelongsToMapWorstCase-4 2000000 787 ns/op
BenchmarkBelongsToSwitchWorstCase-4 2000000000 0.35 ns/op
BenchmarkBelongsToListWorstCase-4 100000000 14.7 ns/op
BenchmarkBelongsToMapBestCase-4 2000000 683 ns/op
BenchmarkBelongsToSwitchBestCase-4 100000000 10.6 ns/op
BenchmarkBelongsToListBestCase-4 100000000 10.4 ns/op
Switch gana todo el camino, el peor de los casos es increíblemente más rápido que el mejor de los casos. Los mapas son lo peor y la lista está más cerca de cambiar.
Entonces, la moraleja es: si tiene una lista estática, razonablemente pequeña, la declaración de cambio es el camino a seguir.
:
lugar de ,
en la declaración de cambio? ¿Lo hace más rápido?
case
declaraciones en lugar de un solo caso. Los resultados son sensiblemente iguales con ambas funciones.
Otra opción es usar un mapa como conjunto. Utiliza solo las teclas y hacer que el valor sea algo así como un booleano que siempre es cierto. Luego puede verificar fácilmente si el mapa contiene la clave o no. Esto es útil si necesita el comportamiento de un conjunto, donde si agrega un valor varias veces es solo en el conjunto una vez.
Aquí hay un ejemplo simple donde agrego números aleatorios como claves a un mapa. Si el mismo número se genera más de una vez, no importa, solo aparecerá en el mapa final una vez. Luego utilizo un simple if check para ver si una clave está en el mapa o no.
package main
import (
"fmt"
"math/rand"
)
func main() {
var MAX int = 10
m := make(map[int]bool)
for i := 0; i <= MAX; i++ {
m[rand.Intn(MAX)] = true
}
for i := 0; i <= MAX; i++ {
if _, ok := m[i]; ok {
fmt.Printf("%v is in map\n", i)
} else {
fmt.Printf("%v is not in map\n", i)
}
}
}
Esto es lo más cerca que puedo llegar a la sensación natural del operador "en" de Python. Tienes que definir tu propio tipo. Luego puede ampliar la funcionalidad de ese tipo agregando un método como "has" que se comporta como cabría esperar.
package main
import "fmt"
type StrSlice []string
func (list StrSlice) Has(a string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
func main() {
var testList = StrSlice{"The", "big", "dog", "has", "fleas"}
if testList.Has("dog") {
fmt.Println("Yay!")
}
}
Tengo una biblioteca de utilidades donde defino algunas cosas comunes como esta para varios tipos de sectores, como los que contienen enteros o mis otras estructuras.
Sí, se ejecuta en tiempo lineal, pero ese no es el punto. El punto es preguntar y aprender qué construcciones de lenguaje común Go tiene y no tiene. Es un buen ejercicio. Si esta respuesta es tonta o útil depende del lector.
strings.Index
) ayuda a que sea más obvio lo que está haciendo el código. Tengo la impresión de que quizás piensas que Pythonin array:
está haciendo algo rápido / mágico. AFAIK no lo es. Hacer explícito el bucle ayuda a que el escritor (y todos los lectores) conozcan y consideren otras implementaciones (por ejemplo, un mapa).