Как узнать положение элемента в срезе?


108

Как определить положение элемента, присутствующего в срезе?

Мне нужно что-то вроде следующего:

type intSlice []int

func (slice intSlice) pos(value int) int {
    for p, v := range slice {
        if (v == value) {
            return p
        }
    }
    return -1
}

2
так в чем вопрос? код не работает?
newacct

8
Я спрашивал, почему кодеры должны сами писать такие общие функции? Я имею в виду, что если мне нужна другая функция для значений с плавающей запятой, я буду вынужден скопировать / вставить эту функцию. Для меня это выглядело странно. Но Кшиштоф Ковальчик уже ответил, что это потому, что у golang нет дженериков.
OCyril

Ваш кусок отсортирован?
дольмен

2
Попробуйте этот источник: gobyexample.com/collection-functions
Виктор

Ответы:


70

К сожалению, для этого нет универсальной библиотечной функции. В Go нет простого способа написать функцию, которая может работать с любым фрагментом.

Ваша функция работает, хотя было бы немного лучше, если бы вы писали ее с использованием range.

Если у вас есть байтовый срез, есть bytes.IndexByte .


3
Я согласен с Эваном. Дополнительный комментарий: более идиоматично возвращать только int, где -1 означает «не найдено» (например, bytes.IndexByte)
Кшиштоф Ковальчик

2
Спасибо. Но я немного ошеломлен :) Я много раз слышал от людей, использующих golang, что он очень хорошо разработан для повышения производительности программистов. И программы go выглядят так же красиво, как и программы на Python :) Так почему же нет единого способа выполнить такую ​​обычную задачу? Я имею в виду, если вы хотите проверить, есть ли в контейнере элемент, вы можете простоif element in collection: do_something()
OCyril

10
Технический ответ таков: потому что в Go нет дженериков. Если бы это было так (и, возможно, в какой-то момент в будущем они появятся), вы могли бы написать общий IndexInSlice, который работает с любым типом, реализующим ==. Ставлю шляпу защитника го: речь идет о среднем опыте. Вы не можете ожидать, что какой-то один язык превзойдет все остальные во всех аспектах. Go является гораздо более продуктивным , чем C, C ++, может быть , даже Java или C # и близко к питону. Это сочетание производительности программиста и генерации собственного кода (то есть скорости), что делает его привлекательным.
Krzysztof Kowalczyk

1
Другой вариант - использовать функции и замыкания более высокого порядка для создания общих функций. Я добавил ответ примером.
Hodza

1
@OCyril Вы должны написать свои собственные обобщения и создать свою собственную библиотеку или провести исследование и найти что-то, что соответствует вашим потребностям. На самом низком уровне функция «найти значение = x в массиве» (PHP, Python или что-то еще) будет выглядеть как версия, указанная в вопросе OP - на низком уровне. Циклы играют центральную роль в программировании такого типа, даже если они скрыты. Go не скрывает этого.
Ян Льюис

54

Вы можете создать универсальную функцию идиоматическим способом:

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

И использование:

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
Мне это нравится, но мне трудно думать об этом таким образом
Децебал

1
Я не думаю, что возврат из- -1за ошибки идиоматичен, вместо этого следует использовать множественный возврат. (Я новичок в голанге, но это то, что я читал)
Тим Абелл,

7
Функции индекса Buildtin в go всегда возвращают -1. Это ожидаемое идиоматическое поведение. Отсутствующий элемент не является ошибкой.
Hodza,

Это фантастика! Очень полезно :) Спасибо!
Gaurav Ojha

12

Вы можете написать функцию;

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

Это возвращает индекс символа / строки, если он соответствует элементу. Если он не найден, возвращает -1.



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

1

Другой вариант - отсортировать фрагмент с помощью пакета сортировки, а затем выполнить поиск того, что вы ищете:

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

печатает

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

Это работает для основных типов, и вы всегда можете реализовать интерфейс сортировки для своего собственного типа, если вам нужно поработать над частью других вещей. См. Http://golang.org/pkg/sort

Но все зависит от того, что вы делаете.


Хорошо, спасибо. Но я думаю, это выглядит странно, если я хочу только проверить, содержит ли срез данный элемент :)
OCyril

3
это не находит исходный индекс; вместо этого он теряет все индексы, переупорядочивая их
newacct

Конечно, поэтому это зависит от использования. Если это просто проверка, то конечно, просто используйте for p, v := range ...и if. Просто хотел указать на вариант.
robothor
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.