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
}

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

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 .


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

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.


6

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


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

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.