From d86be6ef9ca4dfbae92011d5d6cab759c9019512 Mon Sep 17 00:00:00 2001 From: tuannguyen Date: Sun, 6 Aug 2023 18:48:34 +0700 Subject: [PATCH] feat: add the func goDashMap --- collection/map.go | 41 +++++++++++++++++++++ collection/map_test.go | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 collection/map.go create mode 100644 collection/map_test.go diff --git a/collection/map.go b/collection/map.go new file mode 100644 index 0000000..de496d4 --- /dev/null +++ b/collection/map.go @@ -0,0 +1,41 @@ +package collection + +import ( + "reflect" + + "github.com/warriors-vn/go-dash/constants" +) + +// goDashMap applies the iteratee function to each element in the input array and returns a new slice of results. +// It takes an array-like data structure and an iteratee function that operates on each element. +// The iteratee function should have the signature func(elementType) mappedElementType. +// The function returns a new slice of mapped elements and an error if any occurs. +func goDashMap(array, iteratee interface{}) (interface{}, error) { + arrValue, iterateeValue := reflect.ValueOf(array), reflect.ValueOf(iteratee) + + if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array { + return nil, constants.ErrNotSlice + } + + if iterateeValue.Kind() != reflect.Func { + return nil, constants.ErrNotFunction + } + + numParams := iterateeValue.Type().NumIn() + if numParams != 1 { + return nil, constants.ErrNotSupport + } + + kind, result := iterateeValue.Type().In(0).Kind(), reflect.MakeSlice(arrValue.Type(), 0, 0) + if kind == reflect.Interface { + return nil, constants.ErrNotSupport + } + for i := 0; i < arrValue.Len(); i++ { + res := iterateeValue.Call([]reflect.Value{reflect.ValueOf(arrValue.Index(i).Interface())}) + if len(res) > 0 && res[0].Kind() == kind { + result = reflect.Append(result, res[0]) + } + } + + return result.Interface(), nil +} diff --git a/collection/map_test.go b/collection/map_test.go new file mode 100644 index 0000000..5298ad8 --- /dev/null +++ b/collection/map_test.go @@ -0,0 +1,82 @@ +package collection + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/warriors-vn/go-dash/constants" +) + +func Test_goDashMap_valid_int(t *testing.T) { + result, err := goDashMap([]int{1, 2, 3, 4}, func(n int) int { + return n * n + }) + + assert.Equal(t, []int{1, 4, 9, 16}, result) + assert.Nil(t, err) +} + +func Test_goDashMap_valid_response_func_invalid(t *testing.T) { + result, err := goDashMap([]int{1, 2, 3, 4}, func(n int) bool { + return n%2 == 0 + }) + + assert.Equal(t, []int{}, result) + assert.Nil(t, err) +} + +func Test_goDashMap_valid_string(t *testing.T) { + result, err := goDashMap([]string{"a", "b", "c"}, func(n string) string { + return n + n + }) + + assert.Equal(t, []string{"aa", "bb", "cc"}, result) + assert.Nil(t, err) +} + +func Test_goDashMap_valid_struct(t *testing.T) { + type User struct { + Name string + Age int + } + result, err := goDashMap([]*User{{Name: "Kakalot", Age: 26}, {Name: "Vegeta", Age: 27}, {Name: "Trunk", Age: 10}}, func(n *User) *User { + return &User{Name: n.Name, Age: n.Age * 2} + }) + + assert.Equal(t, []*User{{Name: "Kakalot", Age: 52}, {Name: "Vegeta", Age: 54}, {Name: "Trunk", Age: 20}}, result) + assert.Nil(t, err) +} + +func Test_goDashMap_invalid_array_not_slice(t *testing.T) { + result, err := goDashMap(true, func(n int) int { + return n * 2 + }) + + assert.Equal(t, nil, result) + assert.Equal(t, constants.ErrNotSlice, err) +} + +func Test_goDashMap_invalid_predicate_not_func(t *testing.T) { + result, err := goDashMap([]string{"a", "b", "c"}, true) + + assert.Equal(t, nil, result) + assert.Equal(t, constants.ErrNotFunction, err) +} + +func Test_goDashMap_invalid_param_predicate_limit(t *testing.T) { + result, err := goDashMap([]string{"a", "b", "c"}, func(n string, m int) bool { + return n == "a" || m%2 == 0 + }) + + assert.Equal(t, nil, result) + assert.Equal(t, constants.ErrNotSupport, err) +} + +func Test_goDashMap_invalid_interface(t *testing.T) { + result, err := goDashMap([]interface{}{"a", "b", "c"}, func(n interface{}) interface{} { + return n + }) + + assert.Equal(t, nil, result) + assert.Equal(t, constants.ErrNotSupport, err) +}