Comment connaître la position de l'élément dans la tranche?

108

Comment déterminer la position d'un élément présent en tranche?

J'ai besoin de quelque chose comme ce qui suit:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}
OCyril
la source
2
alors, quelle est la question? le code ne fonctionne pas?
newacct
8
Je me demandais pourquoi les codeurs devraient-ils écrire eux-mêmes de telles fonctions communes? Je veux dire si je veux une autre fonction pour les valeurs flottantes, je serai obligé de copier / coller cette fonction. Cela me paraissait bizarre. Mais Krzysztof Kowalczyk a déjà répondu que c'est parce que Golang n'a pas de génériques.
OCyril
Votre tranche est-elle triée?
dolmen
2
Essayez cette source: gobyexample.com/collection-functions
Victor

Réponses:

70

Désolé, il n'y a pas de fonction de bibliothèque générique pour faire cela. Go n'a pas un moyen simple d'écrire une fonction qui peut fonctionner sur n'importe quelle tranche.

Votre fonction fonctionne, même si ce serait un peu mieux si vous l'écriviez en utilisant range.

Si vous avez une tranche d'octets, il y a bytes.IndexByte .

Evan Shaw
la source
3
Je suis d'accord avec Evan. Commentaire supplémentaire: il est plus idiomatique de renvoyer juste un int où -1 indique "introuvable" (comme bytes.IndexByte)
Krzysztof Kowalczyk
2
Merci. Mais je suis un peu débordé :) J'ai entendu à plusieurs reprises de la part de personnes utilisant golang, qu'il était très bien conçu pour augmenter la productivité des programmeurs. Et les programmes go sont aussi beaux que ceux en python :) Alors pourquoi n'y a-t-il pas de moyen commun de faire une tâche aussi courante? Je veux dire, si vous voulez vérifier si le conteneur a un élément, vous pouvez simplementif element in collection: do_something()
OCyril
10
La réponse technique est: parce que Go n'a pas de génériques. Si c'était le cas (et peut-être à un moment donné dans le futur, il les aura), vous auriez pu écrire un IndexInSlice générique qui fonctionne sur n'importe quel type qui implémente ==. Mettre mon chapeau d'avocat Go: il s'agit d'une expérience moyenne. Vous ne pouvez pas vous attendre à ce qu'une seule langue batte toutes les autres langues dans tous les aspects. Go est beaucoup plus productif que C, C ++, peut-être même Java ou C # et proche de python. C'est la combinaison de la productivité du programmeur et de la génération de code natif (c'est-à-dire la vitesse) qui le rend attrayant.
Krzysztof Kowalczyk
1
Une autre option consiste à utiliser des fonctions et des fermetures d'ordre supérieur pour la création de fonctions génériques. J'ai ajouté la réponse avec un exemple.
Hodza
1
@OCyril Vous devez écrire vos propres génériques et créer votre propre bibliothèque ou faire des recherches et trouver quelque chose qui correspond à vos besoins. Au niveau le plus bas, la fonction 'find value = x in array' (PHP, Python ou autre) ressemblera un peu à la version donnée dans la question de l'OP - à un niveau bas. Les boucles sont au cœur de ce type de programmation, même si elles sont masquées. Go ne cache pas ce truc.
Ian Lewis
54

Vous pouvez créer une fonction générique de manière idiomatique:

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

Et l'utilisation:

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
la source
1
J'adore ça, mais j'ai du mal à y penser de cette façon
Decebal
1
Je ne pense pas que le retour -1pour une erreur soit idiomatique, il devrait plutôt utiliser un retour multiple. (Je suis nouveau au golang mais c'est ce que j'ai lu)
Tim Abell
7
Les fonctions d'index Buildtin dans go retournent toujours -1. C'est un comportement idiomatique attendu. L'élément manquant n'est pas une erreur.
Hodza
C'est fantastique! Très utile :) Merci!
Gaurav Ojha
12

Vous pouvez écrire une fonction;

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

Cela renvoie l'index d'un caractère / chaîne s'il correspond à l'élément. S'il n'est pas trouvé, renvoie un -1.

PodTech.io
la source
6

Il n'y a pas de fonction de bibliothèque pour cela. Vous devez coder vous-même.

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

Une autre option consiste à trier la tranche à l'aide du package de tri, puis à rechercher l'élément que vous recherchez:

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

impressions

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

Cela fonctionne pour les types de base et vous pouvez toujours implémenter l'interface de tri pour votre propre type si vous avez besoin de travailler sur une tranche d'autres choses. Voir http://golang.org/pkg/sort

Cela dépend de ce que vous faites.

Robothor
la source
OK merci. Mais je suppose que cela semble bizarre d'utiliser ceci si je veux seulement vérifier si la tranche contient un élément donné :)
OCyril
3
cela ne trouve pas l'index d'origine; il perd plutôt tous les index en les réorganisant
newacct
Bien sûr, c'est pourquoi cela dépend de l'utilisation. S'il ne s'agit que d'un chèque, alors bien sûr, utilisez simplement for p, v := range ...et if. Je voulais juste souligner l'option.
robothor