1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

5 Commits

Author SHA1 Message Date
dudaodong 089fd4e13c feat: add UnionBy for slice 2022-11-05 19:45:34 +08:00
dudaodong 6c40e02324 refactor: clean code 2022-11-05 19:33:56 +08:00
dudaodong a270b1b634 feat: make code clear 2022-11-05 17:09:56 +08:00
dudaodong 260fb795d3 feat: add KeyBy for slice 2022-11-05 16:52:31 +08:00
dudaodong 8c036f830c refactor: remove unuseful code 2022-11-05 16:39:42 +08:00
2 changed files with 83 additions and 79 deletions
+62 -79
View File
@@ -36,7 +36,7 @@ func ContainSubSlice[T comparable](slice, subslice []T) bool {
// Chunk creates an slice of elements split into groups the length of size. // Chunk creates an slice of elements split into groups the length of size.
func Chunk[T any](slice []T, size int) [][]T { func Chunk[T any](slice []T, size int) [][]T {
var result [][]T result := [][]T{}
if len(slice) == 0 || size <= 0 { if len(slice) == 0 || size <= 0 {
return result return result
@@ -95,7 +95,8 @@ func Concat[T any](slice []T, values ...[]T) []T {
// Difference creates an slice of whose element in slice but not in comparedSlice // Difference creates an slice of whose element in slice but not in comparedSlice
func Difference[T comparable](slice, comparedSlice []T) []T { func Difference[T comparable](slice, comparedSlice []T) []T {
var result []T result := []T{}
for _, v := range slice { for _, v := range slice {
if !Contain(comparedSlice, v) { if !Contain(comparedSlice, v) {
result = append(result, v) result = append(result, v)
@@ -123,7 +124,7 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
} }
//DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal). //DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value, otherValue T) bool) []T { func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(value1, value2 T) bool) []T {
result := make([]T, 0) result := make([]T, 0)
getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int { getIndex := func(arr []T, item T, comparison func(v1, v2 T) bool) int {
@@ -180,11 +181,8 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
// Every return true if all of the values in the slice pass the predicate function. // Every return true if all of the values in the slice pass the predicate function.
func Every[T any](slice []T, predicate func(index int, item T) bool) bool { func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
var currentLength int var currentLength int
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
currentLength++ currentLength++
@@ -196,9 +194,6 @@ func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
// None return true if all the values in the slice mismatch the criteria // None return true if all the values in the slice mismatch the criteria
func None[T any](slice []T, predicate func(index int, item T) bool) bool { func None[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
var currentLength int var currentLength int
for i, v := range slice { for i, v := range slice {
@@ -212,39 +207,30 @@ func None[T any](slice []T, predicate func(index int, item T) bool) bool {
// Some return true if any of the values in the list pass the predicate function. // Some return true if any of the values in the list pass the predicate function.
func Some[T any](slice []T, predicate func(index int, item T) bool) bool { func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
if predicate == nil {
panic("predicate func is missing")
}
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
return true return true
} }
} }
return false return false
} }
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function // Filter iterates over elements of slice, returning an slice of all elements pass the predicate function
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T { func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
if predicate == nil {
panic("predicate func is missing")
}
result := make([]T, 0) result := make([]T, 0)
for i, v := range slice { for i, v := range slice {
if predicate(i, v) { if predicate(i, v) {
result = append(result, v) result = append(result, v)
} }
} }
return result return result
} }
// Count iterates over elements of slice, returns a count of all matched elements // Count iterates over elements of slice, returns a count of all matched elements
func Count[T any](slice []T, predicate func(index int, item T) bool) int { func Count[T any](slice []T, predicate func(index int, item T) bool) int {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return 0 return 0
} }
@@ -261,10 +247,6 @@ func Count[T any](slice []T, predicate func(index int, item T) bool) int {
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices // GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) { func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) {
if groupFn == nil {
panic("groupFn func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return make([]T, 0), make([]T, 0) return make([]T, 0), make([]T, 0)
} }
@@ -285,11 +267,7 @@ func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
} }
// GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee. // GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
func GroupWith[T any, U comparable](slice []T, iteratee func(T) U) map[U][]T { func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]T {
if iteratee == nil {
panic("iteratee func is missing")
}
result := make(map[U][]T) result := make(map[U][]T)
for _, v := range slice { for _, v := range slice {
@@ -306,10 +284,6 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(T) U) map[U][]T {
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function. // Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func // If return T is nil then no items matched the predicate func
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return nil, false return nil, false
} }
@@ -332,10 +306,6 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function. // FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func // If return T is nil then no items matched the predicate func
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
if predicate == nil {
panic("predicate func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return nil, false return nil, false
} }
@@ -408,10 +378,6 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
// ForEach iterates over elements of slice and invokes function for each element // ForEach iterates over elements of slice and invokes function for each element
func ForEach[T any](slice []T, iteratee func(index int, item T)) { func ForEach[T any](slice []T, iteratee func(index int, item T)) {
if iteratee == nil {
panic("iteratee func is missing")
}
for i, v := range slice { for i, v := range slice {
iteratee(i, v) iteratee(i, v)
} }
@@ -419,10 +385,6 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
// Map creates an slice of values by running each element of slice thru iteratee function. // Map creates an slice of values by running each element of slice thru iteratee function.
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U { func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
if iteratee == nil {
panic("iteratee func is missing")
}
result := make([]U, len(slice), cap(slice)) result := make([]U, len(slice), cap(slice))
for i, v := range slice { for i, v := range slice {
result[i] = iteratee(i, v) result[i] = iteratee(i, v)
@@ -433,9 +395,6 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
// Reduce creates an slice of values by running each element of slice thru iteratee function. // Reduce creates an slice of values by running each element of slice thru iteratee function.
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T { func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
if iteratee == nil {
panic("iteratee func is missing")
}
if len(slice) == 0 { if len(slice) == 0 {
return initial return initial
@@ -604,12 +563,8 @@ func UpdateAt[T any](slice []T, index int, value T) []T {
// Unique remove duplicate elements in slice. // Unique remove duplicate elements in slice.
func Unique[T comparable](slice []T) []T { func Unique[T comparable](slice []T) []T {
if len(slice) == 0 { result := []T{}
return []T{}
}
// here no use map filter. if use it, the result slice element order is random, not same as origin slice
var result []T
for i := 0; i < len(slice); i++ { for i := 0; i < len(slice); i++ {
v := slice[i] v := slice[i]
skip := true skip := true
@@ -629,11 +584,8 @@ func Unique[T comparable](slice []T) []T {
// UniqueBy call iteratee func with every item of slice, then remove duplicated. // UniqueBy call iteratee func with every item of slice, then remove duplicated.
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T { func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
if len(slice) == 0 { result := []T{}
return []T{}
}
var result []T
for _, v := range slice { for _, v := range slice {
val := iteratee(v) val := iteratee(v)
result = append(result, val) result = append(result, val)
@@ -642,20 +594,39 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
return Unique(result) return Unique(result)
} }
// Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. // Union creates a slice of unique values, in order, from all given slices.
func Union[T comparable](slices ...[]T) []T { func Union[T comparable](slices ...[]T) []T {
if len(slices) == 0 { result := []T{}
return []T{} contain := map[T]struct{}{}
}
// append all slices, then unique it
var allElements []T
for _, slice := range slices { for _, slice := range slices {
allElements = append(allElements, slice...) for _, item := range slice {
if _, ok := contain[item]; !ok {
contain[item] = struct{}{}
result = append(result, item)
}
}
} }
return Unique(allElements) return result
}
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice
func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
result := []T{}
contain := map[V]struct{}{}
for _, slice := range slices {
for _, item := range slice {
val := predicate(item)
if _, ok := contain[val]; !ok {
contain[val] = struct{}{}
result = append(result, item)
}
}
}
return result
} }
// Intersection creates a slice of unique values that included by all slices. // Intersection creates a slice of unique values that included by all slices.
@@ -667,8 +638,6 @@ func Intersection[T comparable](slices ...[]T) []T {
return Unique(slices[0]) return Unique(slices[0])
} }
var result []T
reducer := func(sliceA, sliceB []T) []T { reducer := func(sliceA, sliceB []T) []T {
hashMap := make(map[T]int) hashMap := make(map[T]int)
for _, val := range sliceA { for _, val := range sliceA {
@@ -685,7 +654,7 @@ func Intersection[T comparable](slices ...[]T) []T {
return out return out
} }
result = reducer(slices[0], slices[1]) result := reducer(slices[0], slices[1])
reduceSlice := make([][]T, 2) reduceSlice := make([][]T, 2)
for i := 2; i < len(slices); i++ { for i := 2; i < len(slices); i++ {
@@ -818,14 +787,14 @@ func Without[T comparable](slice []T, values ...T) []T {
return slice return slice
} }
out := make([]T, 0, len(slice)) result := make([]T, 0, len(slice))
for _, v := range slice { for _, v := range slice {
if !Contain(values, v) { if !Contain(values, v) {
out = append(out, v) result = append(result, v)
} }
} }
return out return result
} }
// IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1 // IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1
@@ -854,18 +823,20 @@ func LastIndexOf[T comparable](slice []T, value T) int {
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation // ToSlicePointer returns a pointer to the slices of a variable parameter transformation
func ToSlicePointer[T any](value ...T) []*T { func ToSlicePointer[T any](value ...T) []*T {
out := make([]*T, len(value)) result := make([]*T, len(value))
for i := range value { for i := range value {
out[i] = &value[i] result[i] = &value[i]
} }
return out
return result
} }
// ToSlice returns a slices of a variable parameter transformation // ToSlice returns a slices of a variable parameter transformation
func ToSlice[T any](value ...T) []T { func ToSlice[T any](value ...T) []T {
out := make([]T, len(value)) result := make([]T, len(value))
copy(out, value) copy(result, value)
return out
return result
} }
// AppendIfAbsent only absent append the value // AppendIfAbsent only absent append the value
@@ -875,3 +846,15 @@ func AppendIfAbsent[T comparable](slice []T, value T) []T {
} }
return slice return slice
} }
// KeyBy converts a slice to a map based on a callback function
func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
result := make(map[U]T, len(slice))
for _, v := range slice {
k := iteratee(v)
result[k] = v
}
return result
}
+21
View File
@@ -428,6 +428,17 @@ func TestUnion(t *testing.T) {
assert.Equal([]int{1, 3, 4, 6}, Union(s1)) assert.Equal([]int{1, 3, 4, 6}, Union(s1))
} }
func TestUnionBy(t *testing.T) {
assert := internal.NewAssert(t, "TestUnionBy")
testFunc := func(i int) int {
return i / 2
}
result := UnionBy(testFunc, []int{0, 1, 2, 3, 4, 5}, []int{0, 2, 10})
assert.Equal(result, []int{0, 2, 4, 10})
}
func TestIntersection(t *testing.T) { func TestIntersection(t *testing.T) {
s1 := []int{1, 2, 2, 3} s1 := []int{1, 2, 2, 3}
s2 := []int{1, 2, 3, 4} s2 := []int{1, 2, 3, 4}
@@ -644,3 +655,13 @@ func TestReplaceAll(t *testing.T) {
assert.Equal([]string{"x", "b", "x", "c", "d", "x"}, ReplaceAll(strs, "a", "x")) assert.Equal([]string{"x", "b", "x", "c", "d", "x"}, ReplaceAll(strs, "a", "x"))
assert.Equal([]string{"a", "b", "a", "c", "d", "a"}, ReplaceAll(strs, "e", "x")) assert.Equal([]string{"a", "b", "a", "c", "d", "a"}, ReplaceAll(strs, "e", "x"))
} }
func TestKeyBy(t *testing.T) {
assert := internal.NewAssert(t, "TestKeyBy")
result := KeyBy([]string{"a", "ab", "abc"}, func(str string) int {
return len(str)
})
assert.Equal(result, map[int]string{1: "a", 2: "ab", 3: "abc"})
}