From 30d798366b11466387d918db0145e7359f5710e4 Mon Sep 17 00:00:00 2001 From: donutloop Date: Fri, 7 Jan 2022 13:19:27 +0100 Subject: [PATCH] Slice: find v2 (#17) * If slice len is zero then return false * Convert find to generic form. * If return T is nil then no items matched the predicate func --- README.md | 2 +- README_zh-CN.md | 2 +- slice/slice.go | 27 +++++++++++---------------- slice/slice_test.go | 2 +- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9df4975..5fbfcb2 100644 --- a/README.md +++ b/README.md @@ -401,7 +401,7 @@ func Drop(slice interface{}, n int) interface{} //creates a slice with `n` eleme func Every(slice, function interface{}) bool //return true if all of the values in the slice pass the predicate function, function signature should be func(index int, value interface{}) bool func None(slice, function interface{}) bool // return true if all the values in the slice mismatch the criteria func Filter [T any] (slice []T, fn func(index int, t T) bool) []T //filter slice, fn signature should be func(int, T) bool. -func Find(slice, function interface{}) (interface{}, bool) //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool . +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) //iterates over elements of slice, returning the first one that passes a truth test on function.function signature should be func(index int, value interface{}) bool . func FlattenDeep(slice interface{}) interface{} //flattens slice recursive func ForEach [T any] (slice []T, fn func(index int, t T)) //iterates over elements of slice and invokes function for each element, fn signature should be func(int, T ). func IntSlice(slice interface{}) ([]int, error) //convert value to int slice diff --git a/README_zh-CN.md b/README_zh-CN.md index 25990f5..37307da 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -401,7 +401,7 @@ func DeleteByIndex(slice interface{}, start int, end ...int) (interface{}, error func Drop(slice interface{}, n int) interface{} //创建一个新切片,当n大于0时删除原切片前n个元素,当n小于0时删除原切片后n个元素 func Every(slice, function interface{}) bool //slice中所有元素都符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool func None(slice, function interface{}) bool //slice中所有元素都不符合函数条件时返回true, 否则返回false. 函数签名:func(index int, value interface{}) bool -func Find(slice, function interface{}) (interface{}, bool)//查找slice中第一个符合条件的元素,函数签名:func(index int, value interface{}) bool +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool)//查找slice中第一个符合条件的元素,函数签名:func(index int, value interface{}) bool func Filter(slice, function interface{}) interface{} //过滤slice, 函数签名:func(index int, value interface{}) bool func FlattenDeep(slice interface{}) interface{} //将slice递归为一维切片。 func ForEach(slice, function interface{}) //遍历切片,在每个元素上执行函数,函数签名:func(index int, value interface{}) diff --git a/slice/slice.go b/slice/slice.go index 7a1f38d..6f43f6a 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -167,7 +167,7 @@ func Some(slice, function interface{}) bool { // Filter iterates over elements of slice, returning an slice of all elements `signature` returns truthy for. // The fn signature should be func(int, T) bool. -func Filter [T any] (slice []T, fn func(index int, t T) bool) []T { +func Filter[T any](slice []T, fn func(index int, t T) bool) []T { res := make([]T, 0, 0) for i, v := range slice { if fn(i, v) { @@ -227,30 +227,25 @@ func GroupBy(slice, function interface{}) (interface{}, interface{}) { // Find iterates over elements of slice, returning the first one that passes a truth test on function. // The function signature should be func(index int, value interface{}) bool . -func Find(slice, function interface{}) (interface{}, bool) { - sv := sliceValue(slice) - fn := functionValue(function) - - elemType := sv.Type().Elem() - if checkSliceCallbackFuncSignature(fn, elemType, reflect.ValueOf(true).Type()) { - panic("function param should be of type func(int, " + elemType.String() + ")" + reflect.ValueOf(true).Type().String()) +// If return T is nil then no items matched the predicate func +func Find[T any](slice []T, fn func(index int, t T) bool) (*T, bool) { + if len(slice) == 0 { + return nil, false } index := -1 - for i := 0; i < sv.Len(); i++ { - flag := fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0] - if flag.Bool() { + for i, v := range slice { + if fn(i, v) { index = i break } } if index == -1 { - var none interface{} - return none, false + return nil, false } - return sv.Index(index).Interface(), true + return &slice[index], true } // FlattenDeep flattens slice recursive @@ -279,7 +274,7 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value { // ForEach iterates over elements of slice and invokes function for each element // The fn signature should be func(int, T ). -func ForEach [T any] (slice []T, fn func(index int, t T)) { +func ForEach[T any](slice []T, fn func(index int, t T)) { for i, v := range slice { fn(i, v) } @@ -287,7 +282,7 @@ func ForEach [T any] (slice []T, fn func(index int, t T)) { // Map creates an slice of values by running each element of `slice` thru `function`. // The fn signature should be func(int, T). -func Map [T any, U any] (slice []T, fn func(index int, t T) U) []U { +func Map[T any, U any](slice []T, fn func(index int, t T) U) []U { res := make([]U, len(slice), cap(slice)) for i, v := range slice { res[i] = fn(i, v) diff --git a/slice/slice_test.go b/slice/slice_test.go index c528535..3b948b1 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -220,7 +220,7 @@ func TestFind(t *testing.T) { t.Fatal("found nothing") } - if res != 2 { + if *res != 2 { internal.LogFailedTestInfo(t, "Find", nums, 2, res) t.FailNow() }