如何在切片中找到元素的位置?

如何确定一个元素在切片中的位置?

我需要这样的东西:

type intSlice []int


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

对不起,没有一般的库函数可以这样做。Go 没有一种直接的方法来编写可以在任何片上操作的函数。

您的函数可以正常工作,尽管如果您使用 range编写它会更好一些。

如果恰好有一个字节片,那么就有 字节

另一种选择是使用 sort 包对切片进行排序,然后搜索您要查找的内容:

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

这取决于你在做什么。

这里没有库函数,你必须自己编码。

你可以用惯用的方法创建通用函数:

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

你可以写一个函数;

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

如果字符/字符串与元素匹配,则返回该字符/字符串的索引。如果找不到该字符/字符串,则返回 -1。

您只需迭代切片并检查某个元素是否与您选择的元素匹配。

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

几个月前,我遇到了同样的问题,我用两种方式解决了它:

第一种方法:

func Find(slice interface{}, f func(value interface{}) bool) int {
s := reflect.ValueOf(slice)
if s.Kind() == reflect.Slice {
for index := 0; index < s.Len(); index++ {
if f(s.Index(index).Interface()) {
return index
}
}
}
return -1
}

举例说明:

type UserInfo struct {
UserId          int
}


func main() {
var (
destinationList []UserInfo
userId      int = 123
)
    

destinationList = append(destinationList, UserInfo {
UserId          : 23,
})
destinationList = append(destinationList, UserInfo {
UserId          : 12,
})
    

idx := Find(destinationList, func(value interface{}) bool {
return value.(UserInfo).UserId == userId
})
    

if idx < 0 {
fmt.Println("not found")
} else {
fmt.Println(idx)
}
}

第二种方法计算成本较低:

func Search(length int, f func(index int) bool) int {
for index := 0; index < length; index++ {
if f(index) {
return index
}
}
return -1
}

举例说明:

type UserInfo struct {
UserId          int
}


func main() {
var (
destinationList []UserInfo
userId      int = 123
)
    

destinationList = append(destinationList, UserInfo {
UserId          : 23,
})
destinationList = append(destinationList, UserInfo {
UserId          : 123,
})
    

idx := Search(len(destinationList), func(index int) bool {
return destinationList[index].UserId == userId
})
    

if  idx < 0 {
fmt.Println("not found")
} else {
fmt.Println(idx)
}
}

如果片是 解决了,另一种选择是使用 SearchInts(a []int, x int) int,如果找到了元素索引,它将返回元素索引,如果没有找到元素,则返回元素应该插入的索引。

s := []int{3,2,1}
sort.Ints(s)
fmt.Println(sort.SearchInts(s, 1)) // 0
fmt.Println(sort.SearchInts(s, 4)) // 3

Https://play.golang.org/p/ozhx_ymxstf

Go 支持1.18版本的泛型,它允许您创建如下函数:

func IndexOf[T comparable](collection []T, el T) int {
for i, x := range collection {
if x == el {
return i
}
}
return -1
}

如果您希望能够在您的集合上调用 IndexOf,您也可以从评论中使用@mh-cbon 的技术。

由于 Go 1.18,您还可以像下面这样使用来自 https://pkg.go.dev/golang.org/x/exp/slices的实验性通用切片包:

package main


import "golang.org/x/exp/slices"


func main() {
s := []int{1,2,3,4,5}
wanted := 3
idx := slices.Index(s, wanted)
fmt.Printf("the index of %v is %v", wanted, idx)
}

如果 wanted不在切片中,它将返回 -1。请在 游乐场处测试它。

这是我最喜欢的方式,因为有朝一日它可能会成为标准库的一部分。