Skip to content

Commit

Permalink
✨ feat: map - add new func: TypedKeys, TypedValues, EachTypedMap for …
Browse files Browse the repository at this point in the history
…get typed key or value from map
  • Loading branch information
inhere committed Mar 24, 2024
1 parent 8b32a51 commit dc3c50a
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 19 deletions.
24 changes: 24 additions & 0 deletions maputil/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strconv"
"strings"

"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/reflects"
)

Expand Down Expand Up @@ -193,6 +194,14 @@ func Keys(mp any) (keys []string) {
return
}

// TypedKeys get all keys of the given typed map.
func TypedKeys[K comdef.SimpleType, V any](mp map[K]V) (keys []K) {
for key := range mp {
keys = append(keys, key)
}
return
}

// Values get all values from the given map.
func Values(mp any) (values []any) {
rv := reflect.Indirect(reflect.ValueOf(mp))
Expand All @@ -207,6 +216,14 @@ func Values(mp any) (values []any) {
return
}

// TypedValues get all values from the given typed map.
func TypedValues[K comdef.SimpleType, V any](mp map[K]V) (values []V) {
for _, val := range mp {
values = append(values, val)
}
return
}

// EachAnyMap iterates the given map and calls the given function for each item.
func EachAnyMap(mp any, fn func(key string, val any)) {
rv := reflect.Indirect(reflect.ValueOf(mp))
Expand All @@ -218,3 +235,10 @@ func EachAnyMap(mp any, fn func(key string, val any)) {
fn(key.String(), rv.MapIndex(key).Interface())
}
}

// EachTypedMap iterates the given map and calls the given function for each item.
func EachTypedMap[K comdef.SimpleType, V any](mp map[K]V, fn func(key K, val V)) {
for key, val := range mp {
fn(key, val)
}
}
81 changes: 62 additions & 19 deletions maputil/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,41 +203,40 @@ func TestGetFromAny_sliceSubValue(t *testing.T) {
assert.Nil(t, val)
}

func TestKeys(t *testing.T) {
mp := map[string]any{
"key0": "v0",
"key1": "v1",
"key2": 34,
}
var testMp01 = map[string]any{
"key0": "v0",
"key1": "v1",
"key2": 34,
}

ln := len(mp)
ret := maputil.Keys(mp)
func TestKeys(t *testing.T) {
ln := len(testMp01)
ret := maputil.Keys(testMp01)
assert.Len(t, ret, ln)
assert.Contains(t, ret, "key0")
assert.Contains(t, ret, "key1")
assert.Contains(t, ret, "key2")

ret = maputil.Keys(&mp)
ret = maputil.Keys(&testMp01)
assert.Len(t, ret, ln)
assert.Contains(t, ret, "key0")
assert.Contains(t, ret, "key1")

ret = maputil.Keys(struct {
a string
}{"v"})

assert.Len(t, ret, 0)

t.Run("typed map", func(t *testing.T) {
ret := maputil.TypedKeys(testMp01)
assert.Len(t, ret, ln)
assert.Contains(t, ret, "key0")
})
}

func TestValues(t *testing.T) {
mp := map[string]any{
"key0": "v0",
"key1": "v1",
"key2": 34,
}

ln := len(mp)
ret := maputil.Values(mp)
ln := len(testMp01)
ret := maputil.Values(testMp01)

assert.Len(t, ret, ln)
assert.Contains(t, ret, "v0")
Expand All @@ -247,8 +246,14 @@ func TestValues(t *testing.T) {
ret = maputil.Values(struct {
a string
}{"v"})

assert.Len(t, ret, 0)

t.Run("typed map", func(t *testing.T) {
ret := maputil.TypedValues(testMp01)
assert.Len(t, ret, ln)
assert.Contains(t, ret, "v0")
assert.Contains(t, ret, 34)
})
}

func TestEachAnyMap(t *testing.T) {
Expand Down Expand Up @@ -347,3 +352,41 @@ func TestIssues_109(t *testing.T) {
assert.True(t, ok)
assert.Len(t, ids, 2)
}

func TestEachTypedMap_HappyPath(t *testing.T) {
mp := map[string]int{
"key1": 1,
"key2": 2,
"key3": 3,
}

var keys []string
var values []int

maputil.EachTypedMap(mp, func(key string, val int) {
keys = append(keys, key)
values = append(values, val)
})

assert.Eq(t, []string{"key1", "key2", "key3"}, keys)
assert.Eq(t, []int{1, 2, 3}, values)
}

func TestEachTypedMap_NonStringKeys(t *testing.T) {
mp := map[int]int{
1: 1,
2: 2,
3: 3,
}

var keys []int
var values []int

maputil.EachTypedMap(mp, func(key int, val int) {
keys = append(keys, key)
values = append(values, val)
})

assert.Eq(t, []int{1, 2, 3}, keys)
assert.Eq(t, []int{1, 2, 3}, values)
}
11 changes: 11 additions & 0 deletions maputil/maputil.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ func SimpleMerge(src, dst map[string]any) map[string]any {
return dst
}

// Merge1level merge multi any map[string]any data. only merge one level data.
func Merge1level(mps ...map[string]any) map[string]any {
newMp := make(map[string]any)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}

// func DeepMerge(src, dst map[string]any, deep int) map[string]any { TODO
// }

Expand Down
12 changes: 12 additions & 0 deletions maputil/maputil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ func TestSimpleMerge(t *testing.T) {
assert.Eq(t, "sv2", dm.Str("sub.s2"))
}

func TestMerge1level(t *testing.T) {
ret := maputil.Merge1level(map[string]any{"A": "v0"}, map[string]any{"A": "v1", "B": "v2"})
assert.Len(t, ret, 2)
assert.Eq(t, "v1", ret["A"])

ret = maputil.Merge1level(map[string]any{"A": "v0"}, nil)
assert.Eq(t, "v0", ret["A"])

ret = maputil.Merge1level(nil, map[string]any{"A": "v1", "B": "v2"})
assert.Eq(t, "v1", ret["A"])
}

func TestMergeStringMap(t *testing.T) {
ret := maputil.MergeSMap(map[string]string{"A": "v0"}, map[string]string{"A": "v1"}, false)
assert.Eq(t, map[string]string{"A": "v0"}, ret)
Expand Down

0 comments on commit dc3c50a

Please sign in to comment.