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
}

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 .


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

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.


6

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


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

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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.