Wie finde ich die Elementposition im Slice heraus?

108

Wie bestimmt man die Position eines in Slice vorhandenen Elements?

Ich brauche so etwas wie das Folgende:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}
OCyril
quelle
2
Also, was ist die Frage? funktioniert der Code nicht?
Newacct
8
Ich fragte mich, warum Codierer solche gemeinsamen Funktionen selbst schreiben sollten. Ich meine, wenn ich eine andere Funktion für Float-Werte möchte, muss ich diese Funktion kopieren / einfügen. Das sah komisch für mich aus. Aber Krzysztof Kowalczyk hat bereits geantwortet, dass Golang keine Generika hat.
OCyril
Ist deine Scheibe sortiert?
Dolmen
2
Versuchen Sie diese Quelle: gobyexample.com/collection-functions
Victor

Antworten:

70

Leider gibt es dafür keine generische Bibliotheksfunktion. Go hat keine einfache Möglichkeit, eine Funktion zu schreiben, die auf jedem Slice ausgeführt werden kann.

Ihre Funktion funktioniert, obwohl es etwas besser wäre, wenn Sie sie mit schreiben würden range.

Wenn Sie zufällig ein Byte-Slice haben, gibt es bytes.IndexByte .

Evan Shaw
quelle
3
Ich stimme Evan zu. Zusätzlicher Kommentar: Es ist idiomatischer, nur ein int zurückzugeben, wobei -1 "nicht gefunden" bedeutet (wie bytes.IndexByte)
Krzysztof Kowalczyk
2
Vielen Dank. Aber ich bin ein wenig überwältigt :) Ich habe oft von Leuten gehört, die Golang verwenden, dass es sehr gut entwickelt wurde, um die Produktivität des Programmierers zu steigern. Und go-Programme sehen genauso gut aus wie Python-Programme :) Warum gibt es keinen gemeinsamen Weg, um eine so gemeinsame Aufgabe zu erledigen? Ich meine, wenn Sie überprüfen möchten, ob Container ein Element hat, können Sie einfachif element in collection: do_something()
OCyril
10
Die technische Antwort lautet: Weil Go keine Generika hat. Wenn dies der Fall wäre (und möglicherweise irgendwann in der Zukunft), hätten Sie möglicherweise ein generisches IndexInSlice geschrieben, das für jeden Typ funktioniert, der == implementiert. Putting my Go Advocate Hat: Es geht um eine durchschnittliche Erfahrung. Sie können nicht erwarten, dass eine einzelne Sprache jede andere Sprache in jeder Hinsicht schlägt. Go ist viel produktiver als C, C ++, vielleicht sogar Java oder C # und nahe an Python. Es ist die Kombination aus Programmiererproduktivität und nativer Codegenerierung (dh Geschwindigkeit), die es attraktiv macht.
Krzysztof Kowalczyk
1
Eine andere Möglichkeit besteht darin, Funktionen und Verschlüsse höherer Ordnung zum Erstellen generischer Funktionen zu verwenden. Ich habe die Antwort mit einem Beispiel hinzugefügt.
Hodza
1
@OCyril Sie müssen Ihre eigenen Generika schreiben und Ihre eigene Bibliothek erstellen oder die Recherche durchführen und etwas finden, das Ihren Anforderungen entspricht. Auf der niedrigsten Ebene ähnelt die Funktion 'find value = x in array' (PHP, Python oder was auch immer) in etwa der in der OP-Frage angegebenen Version - auf einer niedrigen Ebene. Schleifen spielen bei dieser Art der Programmierung eine zentrale Rolle, auch wenn sie ausgeblendet sind. Go versteckt dieses Zeug nicht.
Ian Lewis
54

Sie können generische Funktionen auf idiomatische Weise erstellen:

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

Und Verwendung:

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
quelle
1
Ich liebe das, aber ich finde es schwierig, es so zu sehen
Decebal
1
Ich denke nicht, dass die Rückgabe -1für einen Fehler idiomatisch ist, sondern die mehrfache Rückgabe. (Ich bin neu in Golang, aber das habe ich gelesen)
Tim Abell
7
Buildtin-Indexfunktionen in go geben immer -1 zurück. Dies wird idiomatisches Verhalten erwartet. Fehlendes Element ist kein Fehler.
Hodza
Das ist fantastisch! Sehr nützlich :) Danke!
Gaurav Ojha
12

Sie könnten eine Funktion schreiben;

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

Dies gibt den Index eines Zeichens / einer Zeichenfolge zurück, wenn er mit dem Element übereinstimmt. Wenn es nicht gefunden wird, wird -1 zurückgegeben.

PodTech.io
quelle
6

Dafür gibt es keine Bibliotheksfunktion. Sie müssen selbst codieren.

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

Eine andere Möglichkeit besteht darin, das Slice mithilfe des Sortierpakets zu sortieren und dann nach dem gesuchten Objekt zu suchen:

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

druckt

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

Dies funktioniert für die Basistypen und Sie können jederzeit die Sortierschnittstelle für Ihren eigenen Typ implementieren, wenn Sie an einem Teil anderer Dinge arbeiten müssen. Siehe http://golang.org/pkg/sort

Kommt aber darauf an, was du machst.

Robothor
quelle
OK danke. Aber ich denke, es sieht komisch aus, dies zu verwenden, wenn ich nur überprüfen möchte, ob Slice ein bestimmtes Element enthält :)
OCyril
2
Dies findet den ursprünglichen Index nicht. Vielmehr verliert es alle Indizes, indem es sie neu
anordnet
Klar, deshalb kommt es auf die Nutzung an. Wenn es nur ein Scheck ist, dann verwenden Sie einfach for p, v := range ...und if. Ich wollte nur auf die Option hinweisen.
Robothor