Come scoprire la posizione dell'elemento nello slice?


108

Come si determina la posizione di un elemento presente in slice?

Ho bisogno di qualcosa come il seguente:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}

2
allora, qual è la domanda? il codice non funziona?
newacct

8
Mi chiedevo perché i programmatori dovrebbero scrivere da soli funzioni così comuni? Voglio dire, se voglio un'altra funzione per i valori float, sarò costretto a copiare / incollare questa funzione. Questo sembrava strano per me. Ma Krzysztof Kowalczyk ha già risposto che è perché Golang non ha farmaci generici.
OCyril

La tua fetta è ordinata?
dolmen

Risposte:


70

Spiacenti, non esiste una funzione di libreria generica per farlo. Go non ha un modo semplice per scrivere una funzione che può operare su qualsiasi slice.

La tua funzione funziona, anche se sarebbe un po 'meglio se la scrivessi usando range.

Se ti capita di avere una fetta di byte, c'è bytes.IndexByte .


3
Sono d'accordo con Evan. Commento aggiuntivo: è più idiomatico restituire solo un int dove -1 indica "non trovato" (come bytes.IndexByte)
Krzysztof Kowalczyk

2
Grazie. Ma sono un po 'sopraffatto :) Ho sentito molte volte da persone che usano Golang, che è progettato molto bene per aumentare la produttività del programmatore. E i programmi go sono belli come quelli Python :) Allora perché non esiste un modo comune per svolgere un'attività così comune? Voglio dire, se vuoi controllare se il container ha un elemento puoi semplicementeif element in collection: do_something()
OCyril

10
La risposta tecnica è: perché Go non ha farmaci generici. Se lo avesse fatto (e forse in futuro li avrà) avresti potuto scrivere un IndexInSlice generico che funziona su qualsiasi tipo che implementa ==. Metto il cappello da avvocato di Go: si tratta di un'esperienza nella media. Non puoi aspettarti che una singola lingua superi ogni altra lingua in ogni aspetto. Go è molto più produttivo di C, C ++, forse anche Java o C # e vicino a Python. È la combinazione di produttività del programmatore e generazione di codice nativo (cioè velocità) che lo rende attraente.
Krzysztof Kowalczyk

1
Un'altra opzione consiste nell'usare funzioni e chiusure di ordine superiore per la creazione di funzioni generiche. Ho aggiunto la risposta con un esempio.
Hodza

1
@OCyril Devi scrivere i tuoi generici e costruire la tua libreria o fare la ricerca e trovare qualcosa che si adatti alle tue esigenze. Al livello più basso la funzione 'trova valore = x in array' (PHP, Python o qualsiasi altra cosa) assomiglierà in qualche modo alla versione fornita nella domanda dell'OP - a un livello basso. I loop sono centrali in questo tipo di programmazione, anche se sono nascosti. Go non nasconde questa roba.
Ian Lewis

54

Puoi creare funzioni generiche in modo idiomatico:

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

E utilizzo:

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" }))

1
Lo adoro, ma trovo difficile pensare in questo modo
Decebal

1
Non penso che la restituzione -1per un errore sia idiomatica, dovrebbe invece utilizzare più restituzioni. (Sono nuovo a Golang ma è quello che ho letto)
Tim Abell

7
Le funzioni dell'indice buildtin in go restituiscono sempre -1. Questo è un comportamento idiomatico previsto. L'elemento mancante non è un errore.
Hodza

È fantastico! Molto utile :) Grazie!
Gaurav Ojha

12

Potresti scrivere una funzione;

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

Restituisce l'indice di un carattere / stringa se corrisponde all'elemento. Se non viene trovato, restituisce -1.


6

Non esiste una funzione di libreria per questo. Devi codificare da solo.


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

1

Un'altra opzione è ordinare la fetta utilizzando il pacchetto di ordinamento, quindi cercare l'elemento che stai cercando:

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)
}

stampe

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

Funziona per i tipi di base e puoi sempre implementare l'interfaccia di ordinamento per il tuo tipo se devi lavorare su una fetta di altre cose. Vedi http://golang.org/pkg/sort

Dipende da cosa stai facendo però.


Ok grazie. Ma immagino che sia strano usarlo se voglio solo controllare se la fetta contiene un dato elemento :)
OCyril

3
questo non trova l'indice originale; piuttosto perde tutti gli indici riordinandoli
newacct

Certo, ecco perché dipende dall'utilizzo. Se è solo un assegno, allora certo, usa for p, v := range ...e if. Volevo solo sottolineare l'opzione.
robothor
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.