如何在golang切片中搜索元素


77

我有一部分结构。

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"


由于您的Config结构看起来像一个简单的映射,我想指出您可以将任何JSON数据解码为map[string]interface{}。如果您有兴趣,请查看此官方博客文章
tsabsch '16

Answers:


127

一个简单的for循环:

for _, v := range myconfig {
    if v.Key == "key1" {
        // Found!
    }
}

请注意,由于切片的元素类型是a struct(而不是指针),因此如果struct type为“ 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
}

谢谢,我也可以自由使用指针。您认为在这里使用指针来构造会更快吗?我们可以有一个指针数组吗?
编解码器

@ love2code是的,您也可以使用指针切片,或者如果您遍历索引(如我的第二个示例),那么将不会复制值。由你决定。
icza

好的,我创建var myconfig []*Config并使用了您的第一种方法。我希望这是最好的性能选择
编解码器

@ love2code最佳选择性能的明智选择是从中构建一个可以索引的地图。参见编辑后的答案。
icza

20

您可以使用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 crowd[idx].Name == needle {
        fmt.Println("Found:", idx, crowd[idx])
    } else {
        fmt.Println("Found noting: ", idx)
    }
}

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


9

您可以通过将结构KeyValue组件与其在地图上的虚拟键和值部分进行匹配来将结构保存到地图中:

mapConfig := map[string]string{}
for _, v := range myconfig {
   mapConfig[v.Key] = v.Value
}

然后,使用golang逗号ok惯用语可以测试密钥的存在:

if v, ok := mapConfig["key1"]; ok {
    fmt.Printf("%s exists", v)
}   

3

没有库函数。您必须自己编写代码。

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

}

0

正如其他人所评论的那样,您可以使用匿名函数编写自己的过程来解决此问题。

我用两种方法解决它:

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)    
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.