我有一片结构。
type Config struct {
Key string
Value string
}
// I form a slice of the above struct
var myconfig []Config
// unmarshal a response body into the above slice
if err := json.Unmarshal(respbody, &myconfig); err != nil {
panic(err)
}
fmt.Println(config)
这是其输出:
[{key1 test} {web/key1 test2}]
如何搜索这个数组以获取
key="key1"
所在的元素?
golang.org/x/exp/slices
包,其中包含名为 slices.IndexFunc()
的通用“查找”函数:
func IndexFunc[E any](s []E, f func(E) bool) int
IndexFunc 返回满足 f(s[i]) 的第一个索引 i,如果没有满足则返回 -1。
使用:
idx := slices.IndexFunc(myconfig, func(c Config) bool { return c.Key == "key1" })
在Go Playground尝试一下。
在 Go 1.18 之前,如果需要更快的替代方案,请继续阅读:
用一个简单的
for
循环:
for _, v := range myconfig {
if v.Key == "key1" {
// Found!
}
}
请注意,由于切片的元素类型是
struct
(不是指针),因此如果结构类型为“大”,则这可能效率低下,因为循环会将每个访问的元素复制到循环变量中。
仅在索引上使用
range
循环会更快,这可以避免复制元素:
for i := range myconfig {
if myconfig[i].Key == "key1" {
// Found!
}
}
备注:
这取决于您的情况,是否可能存在具有相同
key
的多个配置,但如果没有,如果找到匹配项,您应该 break
退出循环(以避免搜索其他配置)。
for i := range myconfig {
if myconfig[i].Key == "key1" {
// Found!
break
}
}
此外,如果这是一个频繁的操作,您应该考虑从中构建一个
map
,您可以简单地对其进行索引,例如
// Build a config map:
confMap := map[string]string{}
for _, v := range myconfig {
confMap[v.Key] = v.Value
}
// And then to find values by key:
if v, ok := confMap["key1"]; ok {
// Found
}
您可以使用
sort.Slice()
加 sort.Search()
type Person struct {
Name string
}
func main() {
crowd := []Person{{"Zoey"}, {"Anna"}, {"Benni"}, {"Chris"}}
sort.Slice(crowd, func(i, j int) bool {
return crowd[i].Name <= crowd[j].Name
})
needle := "Benni"
idx := sort.Search(len(crowd), func(i int) bool {
return string(crowd[i].Name) >= needle
})
if idx < len(crowd) && crowd[idx].Name == needle {
fmt.Println("Found:", idx, crowd[idx])
} else {
fmt.Println("Found noting: ", idx)
}
}
您可以通过将 struct
Key
和 Value
组件与映射上的虚构键和值部分相匹配,将结构保存到映射中:
mapConfig := map[string]string{}
for _, v := range myconfig {
mapConfig[v.Key] = v.Value
}
然后使用 golang comma ok 习惯用法,您可以测试密钥是否存在:
if v, ok := mapConfig["key1"]; ok {
fmt.Printf("%s exists", v)
}
没有相应的库函数。你必须自己编码。
for _, value := range myconfig {
if value.Key == "key1" {
// logic
}
}
工作代码:https://play.golang.org/p/IJIhYWROP_
package main
import (
"encoding/json"
"fmt"
)
func main() {
type Config struct {
Key string
Value string
}
var respbody = []byte(`[
{"Key":"Key1", "Value":"Value1"},
{"Key":"Key2", "Value":"Value2"}
]`)
var myconfig []Config
err := json.Unmarshal(respbody, &myconfig)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v\n", myconfig)
for _, v := range myconfig {
if v.Key == "Key1" {
fmt.Println("Value: ", v.Value)
}
}
}
如果有人像我一样来自 Java 或 C#,这就是我最终所做的:
type Person struct {
Name string
Age int
}
// create slice of people
var people []Person = []Person{
{"Tono", 33},
{"Regina", 25},
{"Bob", 40},
}
// find person where its Name equals to Bob <------------------
bob := FirstOrDefault(people, func(p *Person) bool { return p.Name == "Bob" })
if bob != nil {
fmt.Printf("Found bob: %v \n", *bob)
} else {
fmt.Println("could not find bob")
}
peopleOlderThan30 := Where(people, func(p *Person) bool { return p.Age > 30 })
fmt.Println("People older than 30 are:")
for _, element := range peopleOlderThan30 {
fmt.Println(*element)
}
我能够在这些函数的帮助下运行该代码:
func FirstOrDefault[T any](slice []T, filter func(*T) bool) (element *T) {
for i := 0; i < len(slice); i++ {
if filter(&slice[i]) {
return &slice[i]
}
}
return nil
}
func Where[T any](slice []T, filter func(*T) bool) []*T {
var ret []*T = make([]*T, 0)
for i := 0; i < len(slice); i++ {
if filter(&slice[i]) {
ret = append(ret, &slice[i])
}
}
return ret
}
这是一个基于@Tarion 答案的简单函数。
func findProgram (programs []Program, id uint) (Program, error) {
sort.Slice(programs, func(i, j int) bool {
return programs[i].ID <= programs[j].ID
})
idx := sort.Search(len(programs), func(i int) bool {
return programs[i].ID >= id
})
if idx < len(programs) && programs[idx].ID == id {
return programs[idx], nil
} else {
return Program{}, fmt.Errorf("program not found")
}
}
正如其他人之前评论的那样,您可以使用匿名函数编写自己的程序来解决此问题。
我用了两种方法来解决:
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)
}
}
检查切片中的每个元素,包括子字符串。 不区分大小写。
package main
import (
"fmt"
"strings"
)
func findSubstring(sliceStrings []string, substring string) []string {
substring = strings.ToLower(substring)
var matches []string
for _, v := range sliceStrings {
if strings.Contains(strings.ToLower(v), substring) {
matches = append(matches, v)
}
}
return matches
}
func main() {
sliceStrings := []string{"Hello", "World", "world2", "golang"}
substring := "oRl"
matches := findSubstring(sliceStrings, substring)
for _, value := range matches {
fmt.Println(value)
}
}