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
}

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 .


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

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.



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

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.