Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加函数ToMap, ToMapV #249

Merged
merged 16 commits into from
Mar 31, 2024
51 changes: 51 additions & 0 deletions slice/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,57 @@ func Map[Src any, Dst any](src []Src, m func(idx int, src Src) Dst) []Dst {
return dst
}

// 将[]Ele映射到map[Key]Ele
// 从Ele中提取Key的函数fn由使用者提供
//
// 注意:
// 如果出现 i < j
// 设:
//
// key_i := fn(elements[i])
// key_j := fn(elements[j])
//
// 满足key_i == key_j 的情况,则在返回结果的resultMap中
// resultMap[key_i] = val_j
//
// 即使传入的字符串为nil,也保证返回的map是一个空map而不是nil
func ToMap[Ele any, Key comparable](
elements []Ele,
fn func(element Ele) Key,
) map[Key]Ele {
return ToMapV(
elements,
func(element Ele) (Key, Ele) {
return fn(element), element
})
}

// 将[]Ele映射到map[Key]Val
// 从Ele中提取Key和Val的函数fn由使用者提供
//
// 注意:
// 如果出现 i < j
// 设:
//
// key_i, val_i := fn(elements[i])
// key_j, val_j := fn(elements[j])
//
// 满足key_i == key_j 的情况,则在返回结果的resultMap中
// resultMap[key_i] = val_j
//
// 即使传入的字符串为nil,也保证返回的map是一个空map而不是nil
func ToMapV[Ele any, Key comparable, Val any](
elements []Ele,
fn func(element Ele) (Key, Val),
) (resultMap map[Key]Val) {
resultMap = make(map[Key]Val, len(elements))
for _, element := range elements {
k, v := fn(element)
resultMap[k] = v
}
return
}

// 构造map
func toMap[T comparable](src []T) map[T]struct{} {
var dataMap = make(map[T]struct{}, len(src))
Expand Down
245 changes: 245 additions & 0 deletions slice/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,248 @@ func ExampleFilterMap() {
fmt.Println(dst)
// Output: [1 3]
}

func TestToMapV(t *testing.T) {
t.Run("integer-string to map[int]int", func(t *testing.T) {
elements := []string{"1", "2", "3", "4", "5"}
resMap := ToMapV(elements, func(str string) (int, int) {
num, _ := strconv.Atoi(str)
return num, num
})
epectedMap := map[int]int{
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
}
assert.Equal(t, epectedMap, resMap)
})
t.Run("struct<string, string, int> to map[string]struct<string, string, int>", func(t *testing.T) {
type eleType struct {
A string
B string
C int
}
elements := []eleType{
{
A: "a",
B: "b",
C: 1,
},
{
A: "c",
B: "d",
C: 2,
},
}
resMap := ToMapV(elements, func(ele eleType) (string, eleType) {
return ele.A, ele
})
epectedMap := map[string]eleType{
"a": {
A: "a",
B: "b",
C: 1,
},
"c": {
A: "c",
B: "d",
C: 2,
},
}
assert.Equal(t, epectedMap, resMap)
})

t.Run("struct<string, string, int> to map[string]struct<string, string, int>, 重复的key", func(t *testing.T) {
type eleType struct {
A string
B string
C int
}
elements := []eleType{
{
A: "a",
B: "b",
C: 1,
},
{
A: "c",
B: "d",
C: 2,
},
{
A: "a",
B: "d",
C: 3,
},
}
resMap := ToMapV(elements, func(ele eleType) (string, eleType) {
return ele.A, ele
})
epectedMap := map[string]eleType{
"a": {
A: "a",
B: "d",
C: 3,
},
"c": {
A: "c",
B: "d",
C: 2,
},
}
assert.Equal(t, epectedMap, resMap)
})

t.Run("传入nil slice,返回空map", func(t *testing.T) {
var elements []string = nil
resMap := ToMapV(elements, func(str string) (int, int) {
num, _ := strconv.Atoi(str)
return num, num
})
epectedMap := make(map[int]int)
assert.Equal(t, epectedMap, resMap)
})
}

func TestToMap(t *testing.T) {
t.Run("integer-string to map[int]string", func(t *testing.T) {
elements := []string{"1", "2", "3", "4", "5"}
resMap := ToMap(elements, func(str string) int {
num, _ := strconv.Atoi(str)
return num
})
epectedMap := map[int]string{
1: "1",
2: "2",
3: "3",
4: "4",
5: "5",
}
assert.Equal(t, epectedMap, resMap)
})
t.Run("struct<string, string, int> to map[string]struct<string, string, int>", func(t *testing.T) {
type eleType struct {
A string
B string
C int
}
elements := []eleType{
{
A: "a",
B: "b",
C: 1,
},
{
A: "c",
B: "d",
C: 2,
},
}
resMap := ToMap(elements, func(ele eleType) string {
return ele.A
})
epectedMap := map[string]eleType{
"a": {
A: "a",
B: "b",
C: 1,
},
"c": {
A: "c",
B: "d",
C: 2,
},
}
assert.Equal(t, epectedMap, resMap)
})

t.Run("struct<string, string, int> to map[string]struct<string, string, int>, 重复的key", func(t *testing.T) {
type eleType struct {
A string
B string
C int
}
elements := []eleType{
{
A: "a",
B: "b",
C: 1,
},
{
A: "c",
B: "d",
C: 2,
},
}
resMap := ToMap(elements, func(ele eleType) string {
return ele.A
})
epectedMap := map[string]eleType{
"a": {
A: "a",
B: "b",
C: 1,
},
"c": {
A: "c",
B: "d",
C: 2,
},
}
assert.Equal(t, epectedMap, resMap)
})

t.Run("传入nil slice,返回空map", func(t *testing.T) {
var elements []string = nil
resMap := ToMap(elements, func(str string) int {
num, _ := strconv.Atoi(str)
return num
})
epectedMap := make(map[int]string)
assert.Equal(t, epectedMap, resMap)
})
}

func ExampleToMap() {
elements := []string{"1", "2", "3", "4", "5"}
resMap := ToMap(elements, func(str string) int {
num, _ := strconv.Atoi(str)
return num
})
fmt.Println(resMap)
// Output: map[1:1 2:2 3:3 4:4 5:5]
}

func ExampleToMapV() {
type eleType struct {
A string
B string
C int
}
type eleTypeOut struct {
A string
B string
}
elements := []eleType{
{
A: "a",
B: "b",
C: 1,
},
{
A: "c",
B: "d",
C: 2,
},
}
resMap := ToMapV(elements, func(ele eleType) (string, eleTypeOut) {
return ele.A, eleTypeOut{
A: ele.A,
B: ele.B,
}
})
fmt.Println(resMap)
// Output: map[a:{a b} c:{c d}]
}
Loading