go 如何写一个通用的方法,将一个结构体切片,根据 id 字段,转为 map 结构
rt
比如:
定义结构体
type S struct {
ID int64
Name string
}
有切片
[]S{
{
ID: 1,
Name: "1",
},
{
ID: 2,
Name: "2",
},
}
需要转为
map[int64]S {
1: {
ID: 1,
Name: "1",
},
2: {
ID: 2,
Name: "2",
},
}
当然,要求这个方法是通用的
感谢 @jitongxi 提供的方法
go.dev/play/p/WHa2CfMO3Lr
刚发现别的帖子哈哈哈哈 现学现卖
www.hesudu.com/t/917480#reply0
aicodehelper.com/tools/index.html#/#v2ex
答:
// 将一个结构体切片,根据 id 字段,转为 map 结构
func SliceToMap(s []S) map[int64]S {
m := make(map[int64]S)
for _,v := range s {
m[v.ID] = v
}
return m
} 😝 😝 😝
遍历 slice 转为 map ,取出 ID 放新 map
func ToMap[T interface{}](slice []T, getID func(T) string) map[string]T {
if len(slice) == 0 {
return nil
}
mp := make(map[string]T, len(slice))
for _, obj := range slice {
id := getID(obj)
mp[id] = obj
}
return mp
}
type A struct {
ID string
Value string
}
func main() {
sliceA := []A{
{
ID: "1",
Value: "a",
},
{
ID: "2",
Value: "b",
},
{
ID: "3",
Value: "c",
},
}
result := ToMap(sliceA, func(t A) string {
return t.ID
})
fmt.Println(result)
}随手写的 大概是这个意思吧
- struct (marshal) -> json
- json (unmarshal)-> map
需要泛型
反射?
type Row[K any] interface {
GetID() K
}
func ToMap[K comparable, V Row[K]](rows []V) map[K]V {
var m = make(map[K]V, len(rows))
for i, v := range rows {
m[v.GetID()] = rows[i]
}
return m
}
func convertSliceToMap(slice []MyStruct) map[int]MyStruct {
result := make(map[int]MyStruct)
for _, item := range slice {
result[item.id] = item
}
return result
}
func ToMap2(d []interface{}, getID func(interface{}) interface{}) map[interface{}]interface{} {
mp := make(map[interface{}]interface{}, len(d))
for _, o := range d {
mp[getID(o)] = o
}
return mp
}
func SliceToMap(slice interface{}, fieldName string) interface{} {
// 检查 slice 是否为空
s := reflect.ValueOf(slice)
if s.Len() == 0 {
return reflect.MakeMap(reflect.MapOf(reflect.TypeOf(s.Index(0).FieldByName(fieldName).Interface()).Elem(), reflect.TypeOf(slice).Elem())).Interface()
}
// 获取结构体类型信息和 id 字段的索引值
st := s.Index(0).Type()
idIndex := -1
for i := 0; i < st.NumField(); i++ {
if st.Field(i).Name == fieldName {
idIndex = i
break
}
}
if idIndex == -1 {
panic(fmt.Sprintf("Field %s not found in struct %s", fieldName, st.Name()))
}
// 构建 map
m := reflect.MakeMap(reflect.MapOf(st.Field(idIndex).Type, st))
for i := 0; i < s.Len(); i++ {
key := s.Index(i).Field(idIndex)
value := s.Index(i)
m.SetMapIndex(key, value)
}
return m.Interface()
}
我尝试把 KV 都用泛型,发现它无法自动推导,使用起来很不方便。后来把 key 写成 any 。
使用方法是给需要转 map 的 struct 加一个取 key 的方法,然后就能调用函数一行转了。
// Mappable can be converted to a Map, and it is usually a struct with a unique primary key field.
// Please implement a method named UniqueKey() that returns a key that can be used in Map.
type Mappable interface {
UniqueKey() any
}
// ConvertToMap can convert an array of struct to map
func ConvertToMap[E Mappable](s []E) map[any]E {
m := make(map[any]E)
for i := range s {
m[s[i].UniqueKey()] = s[i]
}
return m
}type S struct {
ID int64
Name string
}
func (s S) PrimaryKey() int64 {
return s.ID
}
type PrimaryKey interface {
PrimaryKey() int64
}
func TestStructSliceToMap(t *testing.T) {
list := []PrimaryKey{S{ID: 1, Name: "string1"}, S{ID: 2, Name: "string2"}}
fmt.Println(StructSliceToMap(list))
}
func StructSliceToMap(list []PrimaryKey) (smap map[int64]PrimaryKey) {
smap = make(map[int64]PrimaryKey)
if len(list) == 0 {
return
}
for i := range list {
smap[list[i].PrimaryKey()] = list[i]
}
return
}
问了一下 ChatGPT
func structToMap(obj interface{}) (map[string]interface{}, error) {
objMap := make(map[string]interface{})
s, err := json.Marshal(&obj)
if err != nil {
return nil, err
}
err = json.Unmarshal(s, &objMap)
if err != nil {
return nil, err
}
return objMap, nil
}func slice2map(input []S) map[int]S {
这不是随便写吗?
}
不知道你要的通用是啥意思:
func slice2mapT any map[int]T {
泛型试试?
}
slice 里的 index 和元素的 ID 一定对应吗?不对应怎么处理?
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type S struct {
ID int
Name string
}
func (s S) GetID() int {
return s.ID
}
type IS interface {
S
GetID() int
}
func slice2map[T IS](in []T) map[int]T {
out := map[int]T{}
for _, s := range in {
out[s.GetID()] = s
}
return out
}
func main() {
input := []S{{1, "a"}, {2, "b"}}
fmt.Println(slice2map(input))
}
github.com/samber/lo 请
有谁能试一下,让 chatgpt 做这事
你的这个需求前面那几个简单的就可以了,如果要做复杂的映射,我一般这么写
如果你写过类似函数式的东西应该知道啥意思
func SliceToMap[U comparable, T, G any](s []T, keySelector func(int, T) U, valueMapper func(int, T) G) map[U]G {
m := make(map[U]G)
for i, v := range s {
m[keySelector(i, v)] = valueMapper(i, v)
}
return m
}
func Usage() {
type named struct {
Name string
Value string
}
type additional struct {
Age int
Name string
Value string
}
s := []named{{"1", "1"}, {"2", "2"}, {"3", "3"}}
targetMap := SliceToMap(s,
func(idx int, v named) string { return v.Name },
func(idx int, v named) additional { return additional{idx, v.Name, v.Value} })
}假设你有一个结构体类型为 Person ,其中有一个字段 id ,类型为 int ,表示人员的唯一标识符。你可以编写一个通用的方法,将一个[]Person 类型的切片,根据 id 字段,转换成一个 map[int]Person 类型的映射表。以下是一个示例实现:
type Person struct {
id int
name string
age int
}
func SliceToMapByID(slice interface{}) (map[int]interface{}, error) {
value := reflect.ValueOf(slice)
if value.Kind() != reflect.Slice {
return nil, errors.New("input is not a slice")
}
mapValue := reflect.MakeMapWithSize(reflect.MapOf(reflect.TypeOf(int(0)), value.Type().Elem()), value.Len())
for i := 0; i < value.Len(); i++ {
elem := value.Index(i)
id := elem.FieldByName("id").Interface().(int)
mapValue.SetMapIndex(reflect.ValueOf(id), elem)
}
return mapValue.Interface().(map[int]interface{}), nil
}
这个方法的输入参数是一个空接口类型,可以接受任何类型的切片作为输入。使用反射来处理输入参数的类型,并检查它是否为切片类型。如果是,就创建一个空的映射表,然后遍历切片中的每个元素,提取它的 id 字段的值,并将该元素添加到映射表中。最后返回一个 map[int]interface{}类型的映射表和一个 error 类型的错误(如果有的话)。
请注意,由于使用了反射,这个方法的性能可能不是非常高效,特别是对于大型切片来说。因此,如果你知道你的切片类型是[]Person ,你也可以直接编写一个特定类型的方法,而不是使用反射。
哈哈,这题我会,因为我之前写过,用的反射把 ID 取出来。如果用泛型的话,好像不能取出 ID 属性吧。除非有 ID() 方法
根本登不上去,各位怎么解决? 手游加速器 你会来这 不知道怎么给 app 代理吗? 它用的 cdn 被墙了吧 你是想问,本地的东西为什么 app 进去要先检测网…
搞了个 python 虚拟环境 打包的工具,解决 无公网环境安装 python 、不同 Linux 操作系统 Python 环境兼容的问题 github.com/Alfons…
以前给大家介绍过一些非常有意思的杂项资源,今天再给大家介绍一些。(虽然没有上次的多,也算是一个新年礼物吧) 首先,如果你想在你的web页上做一个小提示,你不妨到http://…
合速度