Jak sprawdzić pozycję elementu w plasterku?

108

Jak określić położenie elementu obecnego w plasterku?

Potrzebuję czegoś takiego:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}
OCyril
źródło
2
więc jakie jest pytanie? czy kod nie działa?
newacct
8
Pytałem, dlaczego programiści mieliby sami pisać takie popularne funkcje? Chodzi mi o to, że jeśli chcę inną funkcję dla wartości zmiennoprzecinkowych, będę zmuszony skopiować / wkleić tę funkcję. To wyglądało dla mnie dziwnie. Ale Krzysztof Kowalczyk już odpowiedział, że to dlatego, że golang nie ma generyków.
OCyril
Czy twój kawałek jest posortowany?
dolmen
2
Wypróbuj to źródło: gobyexample.com/collection-functions
Victor

Odpowiedzi:

70

Przepraszamy, nie ma do tego ogólnej funkcji biblioteki. Go nie ma prostego sposobu pisania funkcji, która może działać na dowolnym wycinku.

Twoja funkcja działa, chociaż byłoby trochę lepiej, gdybyś ją napisał za pomocą range.

Jeśli zdarzy się, że masz wycinek bajtu, jest tam bajty.IndexByte .

Evan Shaw
źródło
3
Zgadzam się z Evanem. Dodatkowy komentarz: bardziej idiomatycznie jest zwrócić tylko int, gdzie -1 oznacza "nie znaleziono" (jak bytes.IndexByte)
Krzysztof Kowalczyk
2
Dzięki. Ale jestem trochę przytłoczony :) Wiele razy słyszałem od osób używających golanga, że ​​jest on bardzo dobrze zaprojektowany, aby zwiększyć produktywność programisty. A programy go wyglądają równie ładnie jak te w Pythonie :) Dlaczego więc nie ma powszechnego sposobu na wykonanie tak powszechnego zadania? Chodzi mi o to, że jeśli chcesz sprawdzić, czy kontener ma element, możesz po prostuif element in collection: do_something()
OCyril
10
Techniczna odpowiedź brzmi: ponieważ Go nie ma typów ogólnych. Gdyby tak było (i być może w przyszłości będzie je mieć), mógłbyś napisać ogólny IndexInSlice, który działa na każdym typie, który implementuje ==. Nakładanie kapelusza rzecznika Go: chodzi o przeciętne doświadczenie. Nie możesz oczekiwać, że jeden język pod każdym względem pokona każdy inny język. Go jest znacznie bardziej produktywne niż C, C ++, może nawet Java lub C # i jest zbliżone do Pythona. To połączenie produktywności programisty i natywnego generowania kodu (tj. Szybkości) sprawia, że ​​jest atrakcyjny.
Krzysztof Kowalczyk
1
Inną opcją jest użycie funkcji wyższego rzędu i zamknięć do tworzenia funkcji ogólnych. Dodałem odpowiedź z przykładem.
Hodza
1
@OCyril Musisz napisać własne generyczne i zbudować własną bibliotekę lub przeprowadzić badania i znaleźć coś, co odpowiada Twoim potrzebom. Na najniższym poziomie funkcja „znajdź wartość = x w tablicy” (PHP, Python lub cokolwiek) będzie wyglądać podobnie do wersji podanej w pytaniu OP - na niskim poziomie. Pętle mają zasadnicze znaczenie dla tego rodzaju programowania, nawet jeśli są ukryte. Go nie ukrywa tych rzeczy.
Ian Lewis
54

Możesz stworzyć ogólną funkcję w idiomatyczny sposób:

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

I użycie:

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
źródło
1
Uwielbiam to, ale trudno mi o tym myśleć w ten sposób
Decebal,
1
Nie sądzę, -1aby zwracanie po błędzie było idiomatyczne, zamiast tego należy użyć wielokrotnego powrotu. (Jestem nowy w golang, ale to właśnie przeczytałem)
Tim Abell
7
Funkcje indeksu Buildtin w go zawsze zwracają -1. Jest to oczekiwane idiomatyczne zachowanie. Brakujący element nie jest błędem.
Hodza
To jest fantastyczne! Bardzo przydatne :) Dzięki!
Gaurav Ojha
12

Możesz napisać funkcję;

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

Zwraca indeks znaku / ciągu, jeśli pasuje do elementu. Jeśli nie zostanie znaleziony, zwraca -1.

PodTech.io
źródło
6

Nie ma do tego funkcji bibliotecznej. Musisz kodować samodzielnie.

alessandro
źródło
2
func index(slice []string, item string) int {
    for i, _ := range slice {
        if slice[i] == item {
            return i
        }
    }
    return -1
}
user60679
źródło
1

Inną opcją jest posortowanie plasterka za pomocą pakietu sortowania, a następnie wyszukanie rzeczy, której szukasz:

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

wydruki

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

Działa to dla podstawowych typów i zawsze możesz zaimplementować interfejs sortowania dla własnego typu, jeśli potrzebujesz popracować nad kawałkiem innych rzeczy. Zobacz http://golang.org/pkg/sort

Zależy jednak od tego, co robisz.

robothor
źródło
Ok dzięki. Ale wydaje mi się, że dziwnie to wygląda, jeśli chcę tylko sprawdzić, czy plasterek zawiera dany element :)
OCyril
3
to nie powoduje znalezienia oryginalnego indeksu; raczej traci wszystkie indeksy, zamawiając je ponownie
newacct
Jasne, dlatego zależy to od zastosowania. Jeśli to tylko czek, to pewnie, po prostu użyj for p, v := range ...i if. Chciałem tylko wskazać opcję.
robothor