feat: 优化 slice 包 Filter 和 Map 函数,新增 Reduce 函数
This commit is contained in:
parent
a4ba3f1fa8
commit
5ab990246d
|
@ -0,0 +1,64 @@
|
||||||
|
package slice
|
||||||
|
|
||||||
|
// Filter 根据特定的表达式过滤切片成员
|
||||||
|
// - reserve: 是否保留符合条件的成员
|
||||||
|
// - slice: 待过滤的切片
|
||||||
|
// - expression: 过滤表达式
|
||||||
|
//
|
||||||
|
// 这个函数的作用是遍历输入切片 slice,然后根据 expression 函数的返回值来决定是否保留每个元素。具体来说
|
||||||
|
// - 如果 expression 返回 true 并且 reserve 也是 true,那么元素会被保留
|
||||||
|
// - 如果 expression 返回 false 并且 reserve 是 false,那么元素也会被保留
|
||||||
|
//
|
||||||
|
// 该没有创建新的内存空间或进行元素复制,所以整个操作相当高效。同时,由于 s 和 slice 实际上共享底层的数组,因此这个函数会改变传入的 slice。如果不希望改变原切片,需要在函数调用之前手动复制一份或者使用 FilterCopy 函数。
|
||||||
|
func Filter[V any](reserve bool, slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
if len(slice) == 0 {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
i int
|
||||||
|
j int
|
||||||
|
)
|
||||||
|
for i = 0; i < len(slice); i++ {
|
||||||
|
if expression(i, slice[i]) {
|
||||||
|
if reserve {
|
||||||
|
slice[j] = slice[i]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !reserve {
|
||||||
|
slice[j] = slice[i]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice[:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterT 与 Filter 的功能相同,但是 reserve 被默认为 true
|
||||||
|
func FilterT[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
return Filter(true, slice, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterF 与 Filter 的功能相同,但是 reserve 被默认为 false
|
||||||
|
func FilterF[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
return Filter(false, slice, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterCopy 与 Filter 的功能相同,但是不会改变原切片,而是返回一个新的切片
|
||||||
|
func FilterCopy[V any](reserve bool, slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
var s = make([]V, len(slice))
|
||||||
|
copy(s, slice)
|
||||||
|
return Filter(reserve, s, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterCopyT 与 FilterCopy 的功能相同,但是 reserve 被默认为 true
|
||||||
|
func FilterCopyT[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
return FilterCopy(true, slice, expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterCopyF 与 FilterCopy 的功能相同,但是 reserve 被默认为 false
|
||||||
|
func FilterCopyF[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||||
|
return FilterCopy(false, slice, expression)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package slice_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/slice"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
s = slice.Filter(true, s, func(index int, item int) bool {
|
||||||
|
return item%2 == 0
|
||||||
|
})
|
||||||
|
if len(s) != 2 {
|
||||||
|
t.Error("Filter failed")
|
||||||
|
}
|
||||||
|
if s[0] != 2 {
|
||||||
|
t.Error("Filter failed")
|
||||||
|
}
|
||||||
|
if s[1] != 4 {
|
||||||
|
t.Error("Filter failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterCopy(t *testing.T) {
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
cp := slice.FilterCopy(true, s, func(index int, item int) bool {
|
||||||
|
return item%2 == 0
|
||||||
|
})
|
||||||
|
if len(s) != 5 {
|
||||||
|
t.Error("FilterCopy failed")
|
||||||
|
} else {
|
||||||
|
t.Log(s, cp)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package slice
|
||||||
|
|
||||||
|
// Map 将切片中的每一个元素转换为另一种类型的元素
|
||||||
|
// - slice: 待转换的切片
|
||||||
|
// - converter: 转换函数
|
||||||
|
//
|
||||||
|
// 这不会改变原有的切片,而是返回一个新的切片
|
||||||
|
func Map[V any, T any](slice []V, converter func(index int, item V) T) []T {
|
||||||
|
var s = make([]T, len(slice))
|
||||||
|
for i := 0; i < len(slice); i++ {
|
||||||
|
s[i] = converter(i, slice[i])
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package slice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reduce 将切片中的多个元素组合成一个单一值
|
||||||
|
// - start: 开始索引,如果为负数则从后往前计算,例如:-1 表示从最后一个元素开始向左遍历,1 表示从第二个元素开始
|
||||||
|
// - slice: 待组合的切片
|
||||||
|
// - reducer: 组合函数
|
||||||
|
func Reduce[V any, R generic.Number](start int, slice []V, reducer func(index int, item V, current R) R) (result R) {
|
||||||
|
length := len(slice)
|
||||||
|
|
||||||
|
if start >= length || -start > length {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
for i := length + start; i >= 0; i-- {
|
||||||
|
result = reducer(i, slice[i], result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := start; i < length; i++ {
|
||||||
|
result = reducer(i, slice[i], result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package slice_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/slice"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReduce(t *testing.T) {
|
||||||
|
s := []int{1, 2, 3, 4, 5}
|
||||||
|
sum := slice.Reduce(0, s, func(index int, item int, current int) int {
|
||||||
|
return current + item
|
||||||
|
})
|
||||||
|
t.Log(sum)
|
||||||
|
if sum != 15 {
|
||||||
|
t.Error("Reduce failed")
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,9 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Slice 切片类型
|
||||||
|
type Slice[V any] []V
|
||||||
|
|
||||||
// GetValue 获取特定索引的元素,如果索引超出范围则返回零值
|
// GetValue 获取特定索引的元素,如果索引超出范围则返回零值
|
||||||
func GetValue[V any](slice []V, i int) (v V) {
|
func GetValue[V any](slice []V, i int) (v V) {
|
||||||
if i >= 0 && i < len(slice) {
|
if i >= 0 && i < len(slice) {
|
||||||
|
@ -333,25 +336,3 @@ func SubWithCheck[T any](a, b []T, checkHandle func(a, b T) bool) []T {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter 过滤切片中的元素
|
|
||||||
// - filterHandle 返回 true 表示需要保留
|
|
||||||
func Filter[T any](a []T, filterHandle func(a T) bool) []T {
|
|
||||||
var result []T
|
|
||||||
for _, a := range a {
|
|
||||||
if filterHandle(a) {
|
|
||||||
result = append(result, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapping 将切片中的元素进行转换
|
|
||||||
// - mappingHandle 返回转换后的元素
|
|
||||||
func Mapping[T any, R any](a []T, mappingHandle func(a T) R) []R {
|
|
||||||
var result []R
|
|
||||||
for _, a := range a {
|
|
||||||
result = append(result, mappingHandle(a))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue