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",
},
}
当然,要求这个方法是通用的
1
wueryi 2023-02-20 09:05:25 +08:00
刚发现别的帖子哈哈哈哈 现学现卖
https://www.v2ex.com/t/917480#reply0 https://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 } 😝 😝 😝 |
2
wangsongyan 2023-02-20 09:08:56 +08:00
遍历 slice 转为 map ,取出 ID 放新 map
|
3
sqfphoenix 2023-02-20 09:21:09 +08:00
```
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) } ``` 随手写的 大概是这个意思吧 |
4
jorneyr 2023-02-20 09:23:01 +08:00 1
1. struct (marshal) -> json
2. json (unmarshal)-> map |
5
Nazz 2023-02-20 09:23:46 +08:00 via Android
需要泛型
|
6
yaott2020 2023-02-20 09:30:02 +08:00 via Android
反射?
|
7
Nazz 2023-02-20 09:31:55 +08:00
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 } |
8
sarices 2023-02-20 09:35:46 +08:00
```
func convertSliceToMap(slice []MyStruct) map[int]MyStruct { result := make(map[int]MyStruct) for _, item := range slice { result[item.id] = item } return result } ``` |
9
sparklee 2023-02-20 09:50:05 +08:00
```
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 } ``` |
10
chitanda 2023-02-20 10:02:43 +08:00
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() } |
11
Muninn 2023-02-20 10:10:41 +08:00
我尝试把 KV 都用泛型,发现它无法自动推导,使用起来很不方便。后来把 key 写成 any 。
使用方法是给需要转 map 的 struct 加一个取 key 的方法,然后就能调用函数一行转了。 ```go // 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 } ``` |
12
flywheel 2023-02-20 10:19:09 +08:00
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 } |
13
cexll 2023-02-20 11:49:24 +08:00
问了一下 ChatGPT
```go 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 } ``` |
14
rrfeng 2023-02-20 12:23:31 +08:00
func slice2map(input []S) map[int]S {
这不是随便写吗? } 不知道你要的通用是啥意思: func slice2map[T any](input []T) map[int]T { 泛型试试? } slice 里的 index 和元素的 ID 一定对应吗?不对应怎么处理? |
15
rrfeng 2023-02-20 12:30:28 +08:00
```
// 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)) } ``` |
16
jitongxi 2023-02-20 12:46:01 +08:00 1
|
17
listenfree 2023-02-20 12:51:12 +08:00
有谁能试一下,让 chatgpt 做这事
|
18
pkoukk 2023-02-20 13:59:49 +08:00
你的这个需求前面那几个简单的就可以了,如果要做复杂的映射,我一般这么写
如果你写过类似函数式的东西应该知道啥意思 ```go 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} }) } ``` |
19
kuqma98 2023-02-20 14:33:31 +08:00
@listenfree
假设你有一个结构体类型为 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 ,你也可以直接编写一个特定类型的方法,而不是使用反射。 |
20
yrj 2023-02-20 21:04:28 +08:00
哈哈,这题我会,因为我之前写过,用的反射把 ID 取出来。如果用泛型的话,好像不能取出 ID 属性吧。除非有 ID() 方法
|
21
thinkingbullet 2023-02-21 16:31:39 +08:00
@kuqma98 panic: interface conversion: interface {} is map[int]main.Person, not map[int]interface {}, 这里出问题了:mapValue.Interface().(map[int]interface{})
|