¿Cómo averiguar la posición del elemento en el sector?

108

¿Cómo se determina la posición de un elemento presente en un corte?

Necesito algo como lo siguiente:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}
OCyril
fuente
2
entonces, cual es la pregunta? ¿el código no funciona?
newacct
8
Me preguntaba por qué los codificadores deberían escribir funciones tan comunes por sí mismos. Quiero decir, si quiero otra función para valores flotantes, me veré obligado a copiar / pegar esta función. Esto me pareció extraño. Pero Krzysztof Kowalczyk ya respondió que es porque golang no tiene genéricos.
OCyril
¿Está ordenada su rebanada?
dolmen
2
Pruebe esta fuente: gobyexample.com/collection-functions
Victor

Respuestas:

70

Lo sentimos, no hay una función de biblioteca genérica para hacer esto. Go no tiene una forma sencilla de escribir una función que pueda operar en cualquier segmento.

Tu función funciona, aunque sería un poco mejor si la escribieras usando range.

Si tiene un segmento de bytes, hay bytes.IndexByte .

Evan Shaw
fuente
3
Estoy de acuerdo con Evan. Comentario adicional: es más idiomático devolver solo un int donde -1 indica "no encontrado" (como bytes.IndexByte)
Krzysztof Kowalczyk
2
Gracias. Pero estoy un poco abrumado :) Escuché muchas veces de personas que usan golang, que está muy bien diseñado para aumentar la productividad del programador. Y los programas go se ven tan bien como los de Python :) Entonces, ¿por qué no hay una forma común de hacer una tarea tan común? Quiero decir, si desea verificar si el contenedor tiene un elemento, puede simplementeif element in collection: do_something()
OCyril
10
La respuesta técnica es: porque Go no tiene genéricos. Si lo hiciera (y tal vez en algún momento en el futuro los tenga), podría haber escrito un IndexInSlice genérico que funcione en cualquier tipo que implemente ==. Poner mi sombrero de defensor de Go: se trata de una experiencia normal. No se puede esperar que un solo idioma supere a todos los demás idiomas en todos los aspectos. Go es mucho más productivo que C, C ++, tal vez incluso Java o C # y se acerca a Python. Es la combinación de la productividad del programador y la generación de código nativo (es decir, la velocidad) lo que lo hace atractivo.
Krzysztof Kowalczyk
1
Otra opción es utilizar cierres y funciones de orden superior para la creación de funciones genéricas. Agregué respuesta con un ejemplo.
Hodza
1
@OCyril Tienes que escribir tus propios genéricos y crear tu propia biblioteca o investigar y encontrar algo que se adapte a tus necesidades. En el nivel más bajo, la función 'buscar valor = x en la matriz' (PHP, Python o lo que sea) se parecerá a la versión dada en la pregunta del OP, en un nivel bajo. Los bucles son fundamentales para este tipo de programación, incluso si están ocultos. Go no esconde estas cosas.
Ian Lewis
54

Puede crear una función genérica en forma idiomática:

func SliceIndex(limit int, predicate func(i int) bool) int {
    for i := 0; i < limit; i++ {
        if predicate(i) {
            return i
        }
    }
    return -1
}

Y uso:

xs := []int{2, 4, 6, 8}
ys := []string{"C", "B", "K", "A"}
fmt.Println(
    SliceIndex(len(xs), func(i int) bool { return xs[i] == 5 }),
    SliceIndex(len(xs), func(i int) bool { return xs[i] == 6 }),
    SliceIndex(len(ys), func(i int) bool { return ys[i] == "Z" }),
    SliceIndex(len(ys), func(i int) bool { return ys[i] == "A" }))
Hodza
fuente
1
Amo esto, pero me resulta difícil pensarlo de esta manera
Decebal
1
No creo que regresar -1por un error sea idiomático, debería usar devolución múltiple en su lugar. (Soy nuevo en golang, pero eso es lo que he leído)
Tim Abell
7
Las funciones de índice incorporadas en go siempre devuelven -1. Este es el comportamiento idiomático esperado. El elemento faltante no es un error.
Hodza
¡Esto es fantástico! Muy útil :) ¡Gracias!
Gaurav Ojha
12

Podrías escribir una función;

func indexOf(element string, data []string) (int) {
   for k, v := range data {
       if element == v {
           return k
       }
   }
   return -1    //not found.
}

Esto devuelve el índice de un carácter / cadena si coincide con el elemento. Si no se encuentra, devuelve -1.

PodTech.io
fuente
6

No hay función de biblioteca para eso. Tienes que codificar por tu cuenta.

Alessandro
fuente
2
func index(slice []string, item string) int {
    for i, _ := range slice {
        if slice[i] == item {
            return i
        }
    }
    return -1
}
user60679
fuente
1

Otra opción es ordenar la porción usando el paquete de clasificación y luego buscar lo que está buscando:

package main

import (
    "sort"
    "log"
    )

var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}

func main() {
        data := ints
        a := sort.IntSlice(data[0:])
        sort.Sort(a)
        pos := sort.SearchInts(a, -784)
        log.Println("Sorted: ", a)
        log.Println("Found at index ", pos)
}

huellas dactilares

2009/11/10 23:00:00 Sorted:  [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]
2009/11/10 23:00:00 Found at index  1

Esto funciona para los tipos básicos y siempre puede implementar la interfaz de clasificación para su propio tipo si necesita trabajar en una porción de otras cosas. Ver http://golang.org/pkg/sort

Sin embargo, depende de lo que estés haciendo.

robothor
fuente
OK gracias. Pero supongo que parece extraño usar esto si solo quiero verificar si el segmento contiene el elemento dado :)
OCyril
3
esto no encuentra el índice original; más bien pierde todos los índices al reordenarlos
newacct
Claro, por eso depende del uso. Si es solo un cheque, entonces seguro, solo usa for p, v := range ...y if. Solo quería señalar la opción.
robothor