From c570b99ea72fdead7c062008573689d08c5bfd65 Mon Sep 17 00:00:00 2001 From: tuannguyen Date: Tue, 8 Aug 2023 12:14:58 +0700 Subject: [PATCH] feat: Implement funk.Partition --- partition.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ partition_test.go | 43 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 partition.go create mode 100644 partition_test.go diff --git a/partition.go b/partition.go new file mode 100644 index 0000000..ad7dc43 --- /dev/null +++ b/partition.go @@ -0,0 +1,48 @@ +package funk + +import ( + "reflect" +) + +// Partition separates the elements of the input array into two slices based on the predicate function. +// It takes an array-like data structure and a predicate function that determines the Partition. +// The predicate function should have the signature func(elementType) bool. +// The function returns two new slices: one containing elements that satisfy the predicate, +// and the other containing elements that do not satisfy the predicate. +func Partition(in, predicate interface{}) interface{} { + if !IsCollection(in) { + panic("First parameter must be a collection") + } + + if !IsFunction(predicate, 1, 1) { + panic("Second argument must be function") + } + + inValue, funcValue := reflect.ValueOf(in), reflect.ValueOf(predicate) + + funcType := funcValue.Type() + + if funcType.Out(0).Kind() != reflect.Bool { + panic("Return argument should be a boolean") + } + + result := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(in)), 0, 0) + partitionOne, partitionTwo := reflect.MakeSlice(inValue.Type(), 0, 0), reflect.MakeSlice(inValue.Type(), 0, 0) + + for i := 0; i < inValue.Len(); i++ { + element := inValue.Index(i) + + res := funcValue.Call([]reflect.Value{reflect.ValueOf(element.Interface())}) + if res[0].Interface().(bool) { + partitionOne = reflect.Append(partitionOne, element) + } else { + partitionTwo = reflect.Append(partitionTwo, element) + } + } + + if partitionOne.Len() > 0 || partitionTwo.Len() > 0 { + result = reflect.Append(result, partitionOne, partitionTwo) + } + + return result.Interface() +} diff --git a/partition_test.go b/partition_test.go new file mode 100644 index 0000000..b6f326f --- /dev/null +++ b/partition_test.go @@ -0,0 +1,43 @@ +package funk + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_partition_valid_int(t *testing.T) { + result := Partition([]int{1, 2, 3, 4}, func(n int) bool { + return n%2 == 0 + }) + + assert.Equal(t, [][]int{{2, 4}, {1, 3}}, result) +} + +func Test_partition_valid_float64(t *testing.T) { + result := Partition([]float64{1.1, 2.2, 3.3, 4.4}, func(n float64) bool { + return n > float64(2) + }) + + assert.Equal(t, [][]float64{{2.2, 3.3, 4.4}, {1.1}}, result) +} + +func Test_partition_valid_string(t *testing.T) { + result := Partition([]string{"a", "b", "c"}, func(n string) bool { + return n > "a" + }) + + assert.Equal(t, [][]string{{"b", "c"}, {"a"}}, result) +} + +func Test_partition_valid_struct(t *testing.T) { + type User struct { + Name string + Age int + } + result := Partition([]*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: "Kakalot", Age: 26}, {Name: "Trunk", Age: 10}}, {{Name: "Vegeta", Age: 27}}}, result) +}