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"
|
||||
)
|
||||
|
||||
// Slice 切片类型
|
||||
type Slice[V any] []V
|
||||
|
||||
// GetValue 获取特定索引的元素,如果索引超出范围则返回零值
|
||||
func GetValue[V any](slice []V, i int) (v V) {
|
||||
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
|
||||
}
|
||||
|
||||
// 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