diff --git a/arrutil/any.go b/arrutil/any.go deleted file mode 100644 index 3513daa7e..000000000 --- a/arrutil/any.go +++ /dev/null @@ -1,6 +0,0 @@ -package arrutil - -// alias of interface{} -// -// TIP: cannot add `go:build !go1.18` in file head, that require the go.mod set `go 1.18` -type any = interface{} diff --git a/arrutil/arrutil.go b/arrutil/arrutil.go index 653b87f05..6f2f1bb5a 100644 --- a/arrutil/arrutil.go +++ b/arrutil/arrutil.go @@ -2,9 +2,9 @@ package arrutil import ( - "reflect" "strings" + "github.com/gookit/goutil/comdef" "github.com/gookit/goutil/mathutil" ) @@ -92,29 +92,27 @@ func TrimStrings(ss []string, cutSet ...string) []string { } // GetRandomOne get random element from an array/slice -func GetRandomOne(arr any) interface{} { return RandomOne(arr) } +func GetRandomOne[T any](arr []T) T { return RandomOne(arr) } // RandomOne get random element from an array/slice -func RandomOne(arr any) interface{} { - rv := reflect.ValueOf(arr) - if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { - return arr +func RandomOne[T any](arr []T) T { + if ln := len(arr); ln > 0 { + i := mathutil.RandomInt(0, len(arr)) + return arr[i] } - - i := mathutil.RandomInt(0, rv.Len()) - r := rv.Index(i).Interface() - return r + panic("cannot get value from nil or empty slice") } -// Unique value in the given array, slice. -func Unique(arr any) interface{} { - rv := reflect.ValueOf(arr) - if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { - return arr - } +// Unique value in the given slice data. +func Unique[T ~string | comdef.XintOrFloat](arr []T) []T { + valMap := make(map[T]struct{}, len(arr)) + uniArr := make([]T, 0, len(arr)) - for i := 0; i < rv.Len(); i++ { - // TODO ... + for _, t := range arr { + if _, ok := valMap[t]; !ok { + valMap[t] = struct{}{} + uniArr = append(uniArr, t) + } } - return arr + return uniArr } diff --git a/arrutil/arrutil_test.go b/arrutil/arrutil_test.go index 8122eea66..fbf1103d5 100644 --- a/arrutil/arrutil_test.go +++ b/arrutil/arrutil_test.go @@ -60,7 +60,7 @@ func TestGetRandomOne(t *testing.T) { assert.NotEq(t, intVal, intVal1) // int array - intArray := [6]int{1, 2, 3, 4, 5, 6} + intArray := []int{1, 2, 3, 4, 5, 6} intReturned := arrutil.GetRandomOne(intArray) intReturned1 := arrutil.GetRandomOne(intArray) for intReturned == intReturned1 { @@ -80,19 +80,20 @@ func TestGetRandomOne(t *testing.T) { strVal1 = arrutil.GetRandomOne(strSlice) } - assert.IsType(t, string(""), strVal) + assert.IsType(t, "", strVal) is.True(arrutil.Contains(strSlice, strVal)) - assert.IsType(t, string(""), strVal1) + assert.IsType(t, "", strVal1) is.True(arrutil.Contains(strSlice, strVal1)) assert.NotEq(t, strVal, strVal1) // string array - strArray := [4]string{"aa", "bb", "cc", "dd"} + strArray := []string{"aa", "bb", "cc", "dd"} strReturned := arrutil.GetRandomOne(strArray) strReturned1 := arrutil.GetRandomOne(strArray) for strReturned == strReturned1 { strReturned1 = arrutil.GetRandomOne(strArray) } + assert.IsType(t, "", strReturned) is.True(arrutil.Contains(strArray, strReturned)) assert.IsType(t, "", strReturned1) @@ -106,19 +107,20 @@ func TestGetRandomOne(t *testing.T) { for byteVal == byteVal1 { byteVal1 = arrutil.GetRandomOne(byteSlice) } + assert.IsType(t, byte('a'), byteVal) is.True(arrutil.Contains(byteSlice, byteVal)) assert.IsType(t, byte('a'), byteVal1) is.True(arrutil.Contains(byteSlice, byteVal1)) assert.NotEq(t, byteVal, byteVal1) - // int - invalidIntData := int(404) - invalidIntReturned := arrutil.GetRandomOne(invalidIntData) - assert.IsType(t, int(0), invalidIntReturned) + is.Panics(func() { + arrutil.RandomOne([]int{}) + }) +} - // float - invalidDataFloat := float32(3.14) - invalidFloatReturned := arrutil.GetRandomOne(invalidDataFloat) - assert.IsType(t, float32(3.1), invalidFloatReturned) +func TestUnique(t *testing.T) { + assert.Eq(t, []int{2, 3, 4}, arrutil.Unique[int]([]int{2, 3, 2, 4})) + assert.Eq(t, []uint{2, 3, 4}, arrutil.Unique([]uint{2, 3, 2, 4})) + assert.Eq(t, []string{"ab", "bc", "cd"}, arrutil.Unique([]string{"ab", "bc", "ab", "cd"})) } diff --git a/arrutil/collection_gte118_test.go b/arrutil/collection_gte118_test.go deleted file mode 100644 index 4df29d67d..000000000 --- a/arrutil/collection_gte118_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package arrutil_test - -import ( - "testing" - - "github.com/gookit/goutil/arrutil" - "github.com/gookit/goutil/testutil/assert" -) - -func TestMap(t *testing.T) { - list1 := []map[string]any{ - {"name": "tom", "age": 23}, - {"name": "john", "age": 34}, - } - - flatArr := arrutil.Column(list1, func(obj map[string]any) (val any, find bool) { - return obj["age"], true - }) - - assert.NotEmpty(t, flatArr) - assert.Contains(t, flatArr, 23) - assert.Len(t, flatArr, 2) - assert.Eq(t, 34, flatArr[1]) -} diff --git a/arrutil/collection_lt118.go b/arrutil/collection_lt118.go deleted file mode 100644 index ee6f390c8..000000000 --- a/arrutil/collection_lt118.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !go1.18 -// +build !go1.18 - -package arrutil - -// Map an object list [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...] -func Map(data any, mapFn func(v any) any) []any { - panic("please upgrade to go 1.18+") -} diff --git a/arrutil/collection_test.go b/arrutil/collection_test.go index 1ce50550c..398f7bd7c 100644 --- a/arrutil/collection_test.go +++ b/arrutil/collection_test.go @@ -286,3 +286,19 @@ func TestExceptWhileEmptyReturnsEmpty(t *testing.T) { assert.Eq(t, []string{}, result) assert.NotSame(t, &data, &result, "should always returns new slice") } + +func TestMap(t *testing.T) { + list1 := []map[string]any{ + {"name": "tom", "age": 23}, + {"name": "john", "age": 34}, + } + + flatArr := arrutil.Column(list1, func(obj map[string]any) (val any, find bool) { + return obj["age"], true + }) + + assert.NotEmpty(t, flatArr) + assert.Contains(t, flatArr, 23) + assert.Len(t, flatArr, 2) + assert.Eq(t, 34, flatArr[1]) +} diff --git a/comdef/types.go b/comdef/types.go new file mode 100644 index 000000000..afea26f70 --- /dev/null +++ b/comdef/types.go @@ -0,0 +1,32 @@ +package comdef + +// Int interface type +type Int interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Uint interface type +type Uint interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 +} + +// Xint interface type. all int or uint types +type Xint interface { + // equal: ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint32 | ~uint64 + Int | Uint +} + +// Float interface type +type Float interface { + ~float32 | ~float64 +} + +// IntOrFloat interface type. all int and float types +type IntOrFloat interface { + Int | Float +} + +// XintOrFloat interface type. all (x)int and float types +type XintOrFloat interface { + Int | Uint | Float +} diff --git a/structs/any.go b/structs/any.go deleted file mode 100644 index ba70a9675..000000000 --- a/structs/any.go +++ /dev/null @@ -1,6 +0,0 @@ -package structs - -// alias of interface{} -// -// TIP: cannot add `go:build !go1.18` in file head, that require the go.mod set `go 1.18` -type any = interface{} diff --git a/testutil/assert/any.go b/testutil/assert/any.go deleted file mode 100644 index 5d2083e55..000000000 --- a/testutil/assert/any.go +++ /dev/null @@ -1,6 +0,0 @@ -package assert - -// alias of interface{} -// -// TIP: cannot add `go:build !go1.18` in file head, that require the go.mod set `go 1.18` -type any = interface{}