Skip to content

Commit

Permalink
feat: add the func reject
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenvantuan2391996 committed Aug 6, 2023
1 parent 7e70bfe commit 0468d97
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
43 changes: 43 additions & 0 deletions collection/reject.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package collection

import (
"reflect"

"github.com/warriors-vn/go-dash/constants"
)

// reject returns a new slice containing elements from the input array that do not satisfy the predicate.
// It takes an array-like data structure and a predicate function that determines whether an element should be excluded.
// The predicate function should have the signature func(elementType) bool.
// The function returns the new slice without the excluded elements and an error if any occurs.
func reject(array interface{}, predicate interface{}) (interface{}, error) {
arrValue, predicateValue := reflect.ValueOf(array), reflect.ValueOf(predicate)

if arrValue.Kind() != reflect.Slice && arrValue.Kind() != reflect.Array {
return nil, constants.ErrNotSlice
}

if predicateValue.Kind() != reflect.Func {
return nil, constants.ErrNotFunction
}

numParams := predicateValue.Type().NumIn()
if numParams != 1 {
return nil, constants.ErrNotSupport
}

kind, result := predicateValue.Type().In(0).Kind(), reflect.MakeSlice(arrValue.Type(), 0, 0)
for i := 0; i < arrValue.Len(); i++ {
element := arrValue.Index(i)
if element.Kind() != kind {
return nil, constants.ErrIncompatible
}

res := predicateValue.Call([]reflect.Value{reflect.ValueOf(element.Interface())})
if len(res) > 0 && res[0].Kind() == reflect.Bool && !res[0].Interface().(bool) {
result = reflect.Append(result, element)
}
}

return result.Interface(), nil
}
82 changes: 82 additions & 0 deletions collection/reject_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package collection

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/warriors-vn/go-dash/constants"
)

func Test_reject_valid_int(t *testing.T) {
result, err := reject([]int{1, 2, 3, 4}, func(n int) bool {
return n%2 == 0
})

assert.Equal(t, []int{1, 3}, result)
assert.Nil(t, err)
}

func Test_reject_valid_response_func_not_bool(t *testing.T) {
result, err := reject([]int{1, 2, 3, 4}, func(n int) int {
return n
})

assert.Equal(t, []int{}, result)
assert.Nil(t, err)
}

func Test_reject_valid_string(t *testing.T) {
result, err := reject([]string{"a", "b", "c"}, func(n string) bool {
return n > "a"
})

assert.Equal(t, []string{"a"}, result)
assert.Nil(t, err)
}

func Test_reject_valid_string_string_two(t *testing.T) {
result, err := reject([]string{"a", "b", "c"}, func(n int) bool {
return n%2 == 0
})

assert.Equal(t, nil, result)
assert.Equal(t, constants.ErrIncompatible, err)
}

func Test_reject_valid_struct(t *testing.T) {
type User struct {
Name string
Age int
}
result, err := reject([]*User{{Name: "Kakalot", Age: 26}, {Name: "Vegeta", Age: 27}, {Name: "Trunk", Age: 10}}, func(n *User) bool {
return n.Age%2 == 0
})

assert.Equal(t, []*User{{Name: "Vegeta", Age: 27}}, result)
assert.Nil(t, err)
}

func Test_reject_invalid_array_not_slice(t *testing.T) {
result, err := reject(true, func(n int) bool {
return n%2 == 0
})

assert.Equal(t, nil, result)
assert.Equal(t, constants.ErrNotSlice, err)
}

func Test_reject_invalid_predicate_not_func(t *testing.T) {
result, err := reject([]string{"a", "b", "c"}, true)

assert.Equal(t, nil, result)
assert.Equal(t, constants.ErrNotFunction, err)
}

func Test_reject_invalid_param_predicate_limit(t *testing.T) {
result, err := reject([]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)
}

0 comments on commit 0468d97

Please sign in to comment.