如何使用结构体过滤 []struct 中的结构体?

huangapple go评论82阅读模式
英文:

How to filter []struct with struct?

问题

我定义了这样的结构体:

type Repo struct {
    Key         string `json:"key"`
    Type        string `json:"type"`
    PackageType string `json:"packageType"`
}

而 JSON 数据如下所示:

[
{
"key":"docker-sre",
"type":"LOCAL",
"packageType":"Docker"
},
{
"key":"docker-test",
"type":"REMOTE",
"packageType":"Docker"
},
{
"key":"go-local-dev",
"type":"LOCAL",
"packageType":"Go"
},
{
"key":"helm-cloudops",
"type":"LOCAL",
"packageType":"Helm"
}
]

如何以不同的条件获取正确的数据呢?

func getWantedRepos(conf Repo) ([]Repo, error) {}

func main() {
    getWantedRepos(Repo{
        PackageType: "Docker",
    })

    getWantedRepos(Repo{
        Type:        "LOCAL",
        PackageType: "Go",
    })
}
英文:

I define struct like this:

type Repo struct {
	Key         string `json:"key"`
	Type        string `json:"type"`
	PackageType string `json:"packageType"`
}

And json data is something like

> [
{
"key":"docker-sre",
"type":"LOCAL",
"packageType":"Docker"
},
{
"key":"docker-test",
"type":"REMOTE",
"packageType":"Docker"
},
{
"key":"go-local-dev",
"type":"LOCAL",
"packageType":"Go"
},
{
"key":"helm-cloudops",
"type":"LOCAL",
"packageType":"Helm"
}
]

What is the best way to get the correct data with different conditions?

func getWantedRepos(conf Repo) ([]Repo, error) {}

func main() {
    getWantedRepos(Repo{
		PackageType: "Docker",
	})

    getWantedRepos(Repo{
        Type: "LOCAL",
		PackageType: "Go",
	})
}

答案1

得分: -1

你可以使用内置的reflect包来实现这个功能。以下是示例代码:

main.go

package main

import (
	"fmt"
	"reflect"
)

type Repo struct {
	Key         string `json:"key"`
	Type        string `json:"type"`
	PackageType string `json:"packageType"`
}

var someDatas = []Repo{
	{
		Key:         "test",
		Type:        "test",
		PackageType: "test",
	},
	{
		Key:         "test1",
		Type:        "test1",
		PackageType: "test1",
	},
	{
		Key:         "test",
		Type:        "LOCAL",
		PackageType: "test23",
	},
}

func getWantedRepos(conf map[string]interface{}) []Repo {
	var returned []Repo
	for _, val := range someDatas {
		flag := true
		for k := range conf {
			if !reflect.DeepEqual(reflect.ValueOf(val).FieldByName(k).Interface(), conf[k]) {
				flag = false
				break
			}
		}
		if flag {
			returned = append(returned, val)
		}
	}

	return returned
}

func main() {
	var repos []Repo
	repos = getWantedRepos(map[string]interface{}{
		"Key": "test",
	})

	fmt.Println("1 ============================")
	fmt.Printf("%+v\n", repos)

	repos = getWantedRepos(map[string]interface{}{
		"Type": "LOCAL",
	})
	fmt.Println("2 ============================")
	fmt.Printf("%+v\n", repos)

	repos = getWantedRepos(map[string]interface{}{
		"Type":        "LOCAL",
		"PackageType": "test23",
	})
	fmt.Println("3 ============================")
	fmt.Printf("%+v\n", repos)

	repos = getWantedRepos(map[string]interface{}{
		"Type":        "LOCAL",
		"PackageType": "NONE",
	})
	fmt.Println("4 ============================")
	fmt.Printf("%+v\n", repos)
}

输出结果:

1 ============================
[{Key:test Type:test PackageType:test} {Key:test Type:LOCAL PackageType:test23}]
2 ============================
[{Key:test Type:LOCAL PackageType:test23}]
3 ============================
[{Key:test Type:LOCAL PackageType:test23}]
4 ============================
[]

我使用了map[string]interface{}而不是模型过滤,因为如果你使用模型,例如带有string属性的模型,string的默认值是""。即使你没有初始化属性的值,它也会有""作为默认值,而reflect循环将扫描并尝试将模型与空字符串""匹配,为了避免这种情况,我使用map[string]interface{},这样我们可以更灵活地选择我们想要的属性。

我不知道你有什么测试用例,但如果你从数据库中获取数据,尝试使用WHERE子句而不是像这样手动过滤。

英文:

You can use reflect built-in package to do this. This is the example:

main.go

package main
import (
"fmt"
"reflect"
)
type Repo struct {
Key         string `json:"key"`
Type        string `json:"type"`
PackageType string `json:"packageType"`
}
var someDatas = []Repo{
{
Key:         "test",
Type:        "test",
PackageType: "test",
},
{
Key:         "test1",
Type:        "test1",
PackageType: "test1",
},
{
Key:         "test",
Type:        "LOCAL",
PackageType: "test23",
},
}
func getWantedRepos(conf map[string]interface{}) []Repo {
var returned []Repo
for _, val := range someDatas {
flag := true
for k := range conf {
if !reflect.DeepEqual(reflect.ValueOf(val).FieldByName(k).Interface(), conf[k]) {
flag = false
break
}
}
if flag {
returned = append(returned, val)
}
}
return returned
}
func main() {
var repos []Repo
repos = getWantedRepos(map[string]interface{}{
"Key": "test",
})
fmt.Println("1 ============================")
fmt.Printf("%+v\n", repos)
repos = getWantedRepos(map[string]interface{}{
"Type": "LOCAL",
})
fmt.Println("2 ============================")
fmt.Printf("%+v\n", repos)
repos = getWantedRepos(map[string]interface{}{
"Type":        "LOCAL",
"PackageType": "test23",
})
fmt.Println("3 ============================")
fmt.Printf("%+v\n", repos)
repos = getWantedRepos(map[string]interface{}{
"Type":        "LOCAL",
"PackageType": "NONE",
})
fmt.Println("4 ============================")
fmt.Printf("%+v\n", repos)
}

Output:

1 ============================
[{Key:test Type:test PackageType:test} {Key:test Type:LOCAL PackageType:test23}]
2 ============================
[{Key:test Type:LOCAL PackageType:test23}]
3 ============================
[{Key:test Type:LOCAL PackageType:test23}]
4 ============================
[]

I use map[string]interface{} instead of Model filtering because if you use a model, for example with string attribute, the default value of string is "". Even if you didn't initialize the value of the attribute, it will have "" as the default value, and the reflect for loop will scan through and try to match model with empty string "", so to avoid that, I use map[string]interface so we are more flexible to select attribute we want and vise versa.

I don't know what test case you have, but if you get the datas from database, try to use the WHERE instead of doing it like this.

huangapple
  • 本文由 发表于 2021年12月29日 14:34:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/70515906.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定