Como descobrir a posição do elemento na fatia?

108

Como determinar a posição de um elemento presente na fatia?

Preciso de algo como o seguinte:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}
OCyril
fonte
2
então qual é a pergunta? o código não funciona?
newacct
8
Eu estava perguntando por que os programadores deveriam escrever tais funções comuns sozinhos? Quer dizer, se eu quiser outra função para valores flutuantes, serei forçado a copiar / colar essa função. Isso parecia estranho para mim. Mas Krzysztof Kowalczyk já respondeu que é porque golang não tem genéricos.
OCyril
Sua fatia está classificada?
dolmen de
2
Tente esta fonte: gobyexample.com/collection-functions
Victor

Respostas:

70

Não há função de biblioteca genérica para fazer isso. Go não tem uma maneira direta de escrever uma função que possa operar em qualquer slice.

Sua função funciona, embora seja um pouco melhor se você a escrever usando range.

Se acontecer de você ter uma fatia de byte, haverá bytes.IndexByte .

Evan Shaw
fonte
3
Eu concordo com Evan. Comentário adicional: é mais idiomático retornar apenas um int em que -1 indica "não encontrado" (como bytes.IndexByte)
Krzysztof Kowalczyk
2
Obrigado. Mas estou um pouco sobrecarregado :) Ouvi muitas vezes de pessoas que usam o golang, que ele é muito bem projetado para aumentar a produtividade do programador. E os programas go parecem tão bons quanto os python :) Então, por que não existe uma maneira comum de fazer uma tarefa tão comum? Quer dizer, se você quiser verificar se o contêiner tem um elemento, você pode simplesmenteif element in collection: do_something()
OCyril
10
A resposta técnica é: porque Go não tem genéricos. Se tivesse (e talvez em algum momento no futuro os tenha), você poderia ter escrito um IndexInSlice genérico que funcione em qualquer tipo que implemente ==. Colocando meu chapéu de defensor do Go: é uma experiência média. Você não pode esperar que um único idioma supere todos os outros em todos os aspectos. Go é muito mais produtivo do que C, C ++, talvez até mesmo Java ou C # e quase python. É a combinação de produtividade do programador e geração de código nativo (ou seja, velocidade) que o torna atraente.
Krzysztof Kowalczyk
1
Outra opção é usar funções de ordem superior e encerramentos para a criação de funções genéricas. Adicionei a resposta com um exemplo.
Hodza
1
@OCyril Você deve escrever seus próprios genéricos e construir sua própria biblioteca ou fazer pesquisas e encontrar algo que atenda às suas necessidades. No nível mais baixo, a função 'find value = x in array' (PHP, Python ou qualquer outra) será parecida com a versão dada na pergunta do OP - em um nível baixo. Os loops são fundamentais para esse tipo de programação, mesmo se estiverem ocultos. Go não esconde essas coisas.
Ian Lewis
54

Você pode criar uma função genérica de maneira 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
}

E 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
fonte
1
Amo isso, mas eu acho difícil vir a pensar nisso desta maneira
Decebal
1
Não acho que retornar -1para um erro seja idiomático, ele deve usar o retorno múltiplo. (Eu sou novo no golang, mas é o que li)
Tim Abell
7
As funções do índice buildtin em go sempre retornam -1. Este é um comportamento idiomático esperado. Elemento ausente não é um erro.
Hodza
Isto é fantástico! Muito útil :) Obrigado!
Gaurav Ojha
12

Você pode escrever uma função;

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

Isso retorna o índice de um caractere / string se corresponder ao elemento. Se não for encontrado, retorna -1.

PodTech.io
fonte
6

Não há função de biblioteca para isso. Você tem que codificar sozinho.

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

Outra opção é classificar a fatia usando o pacote de classificação e, em seguida, pesquisar o que você está procurando:

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

estampas

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

Isso funciona para os tipos básicos e você sempre pode implementar a interface de classificação para seu próprio tipo se precisar trabalhar em uma fatia de outras coisas. Veja http://golang.org/pkg/sort

Depende do que você está fazendo.

robothor
fonte
Ok, obrigado. Mas acho que parece estranho usar isso se eu só quiser verificar se a fatia contém o elemento dado :)
OCyril
3
isso não encontra o índice original; em vez disso, ele perde todos os índices ao
reordená
Claro, é por isso que depende do uso. Se for apenas um cheque, então com certeza, use for p, v := range ...e if. Só queria apontar a opção.
robothor