如何在golang切片中搜索元素

x759pob2  于 2023-01-28  发布在  Go
关注(0)|答案(8)|浏览(327)

我有一个结构体切片。

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

我怎样才能搜索这个数组来得到元素where key="key1"

oug3syen

oug3syen1#

从Go语言1.18开始,它增加了泛型支持,有一个golang.org/x/exp/slices包,其中包含一个名为slices.IndexFunc()的泛型"find"函数:

func IndexFunc[E any](s []E, f func(E) bool) int

IndexFunc返回满足f(s [i])的第一个索引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(不是指针),如果结构体类型是"big",则这可能是低效的,因为循环会将每个访问过的元素复制到循环变量中。
只在索引上使用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
}
bpzcxfmw

bpzcxfmw2#

您可以使用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)
    }
}

参见:https://play.golang.org/p/47OPrjKb0g_c

368yc8dk

368yc8dk3#

通过将结构体KeyValue组件与Map上的虚构键和值部分进行匹配,可以将结构体保存到Map中:

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

cnh2zyt34#

没有库函数可以实现这个功能,你必须自己编写代码。

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

}
k3fezbri

k3fezbri5#

如果有人像我一样来自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
}
um6iljoc

um6iljoc6#

正如其他人之前评论的那样,你可以用匿名函数编写自己的过程来解决这个问题。
我用了两种方法来解决它:

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

csbfibhn7#

下面是一个基于@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")
    }
}
js4nwp54

js4nwp548#

检查切片中的每个元素,包括子字符串。不区分大小写。

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

https://go.dev/play/p/m5UAgbvPbbR

相关问题