feat: 新增大量 slice 包和 hash 包的辅助函数
This commit is contained in:
parent
5ab990246d
commit
d7724094d1
|
@ -0,0 +1,27 @@
|
|||
package hash
|
||||
|
||||
// Chunk 将哈希表按照指定大小分块
|
||||
// - m: 待分块的哈希表
|
||||
// - size: 每块的大小
|
||||
func Chunk[K comparable, V any](m map[K]V, size int) []map[K]V {
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
i int
|
||||
j int
|
||||
)
|
||||
chunks := make([]map[K]V, (len(m)-1)/size+1)
|
||||
for i = 0; i < len(m); i += size {
|
||||
chunks[j] = make(map[K]V, size)
|
||||
for key, value := range m {
|
||||
if i <= j*size && j*size < i+size {
|
||||
chunks[j][key] = value
|
||||
}
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package hash
|
||||
|
||||
// RandomDrop 随机删除哈希表中的指定数量的元素
|
||||
// - 该函数会修改原哈希表,如果不想修改原哈希表,请使用 RandomDropCopy
|
||||
func RandomDrop[K comparable, V any](n int, hash map[K]V) map[K]V {
|
||||
if n <= 0 || len(hash) <= n {
|
||||
return hash
|
||||
}
|
||||
for k := range hash {
|
||||
if n <= 0 {
|
||||
break
|
||||
}
|
||||
delete(hash, k)
|
||||
n--
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// RandomDropCopy 随机删除哈希表中的指定数量的元素
|
||||
// - 该函数不会修改原哈希表,如果想修改原哈希表,请使用 RandomDrop
|
||||
func RandomDropCopy[K comparable, V any](n int, m map[K]V) map[K]V {
|
||||
if n <= 0 || len(m) <= n {
|
||||
return map[K]V{}
|
||||
}
|
||||
var nm = make(map[K]V, len(m))
|
||||
for k, v := range m {
|
||||
if n <= 0 {
|
||||
break
|
||||
}
|
||||
nm[k] = v
|
||||
n--
|
||||
}
|
||||
return nm
|
||||
}
|
||||
|
||||
// DropBy 从哈希表中删除指定的元素
|
||||
func DropBy[K comparable, V any](m map[K]V, fn func(key K, value V) bool) map[K]V {
|
||||
for k, v := range m {
|
||||
if fn(k, v) {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// DropByCopy 与 DropBy 功能相同,但是该函数不会修改原哈希表
|
||||
func DropByCopy[K comparable, V any](m map[K]V, fn func(key K, value V) bool) map[K]V {
|
||||
var nm = make(map[K]V, len(m))
|
||||
for k, v := range m {
|
||||
if fn(k, v) {
|
||||
continue
|
||||
}
|
||||
nm[k] = v
|
||||
}
|
||||
return nm
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package hash
|
||||
|
||||
// Each 根据传入的 abort 遍历 m,如果 iterator 返回值与 abort 相同,则停止遍历
|
||||
func Each[K comparable, V any](abort bool, m map[K]V, iterator func(i int, key K, item V) bool) {
|
||||
i := 0
|
||||
for k, v := range m {
|
||||
if iterator(i, k, v) == abort {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// EachT 与 Each 的功能相同,但是 abort 被默认为 true
|
||||
func EachT[K comparable, V any](m map[K]V, iterator func(i int, key K, item V) bool) {
|
||||
Each(true, m, iterator)
|
||||
}
|
||||
|
||||
// EachF 与 Each 的功能相同,但是 abort 被默认为 false
|
||||
func EachF[K comparable, V any](m map[K]V, iterator func(i int, key K, item V) bool) {
|
||||
Each(false, m, iterator)
|
||||
}
|
||||
|
||||
// EachResult 根据传入的 abort 遍历 m,得到遍历的结果,如果 iterator 返回值中的 bool 值与 abort 相同,则停止遍历,并返回当前已积累的结果
|
||||
func EachResult[K comparable, V any, R any](abort bool, m map[K]V, iterator func(i int, key K, item V) (R, bool)) []R {
|
||||
var result []R
|
||||
i := 0
|
||||
for k, v := range m {
|
||||
r, ok := iterator(i, k, v)
|
||||
result = append(result, r)
|
||||
if ok == abort {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EachResultT 与 EachResult 的功能相同,但是 abort 被默认为 true
|
||||
func EachResultT[K comparable, V any, R any](m map[K]V, iterator func(i int, key K, item V) (R, bool)) []R {
|
||||
return EachResult(true, m, iterator)
|
||||
}
|
||||
|
||||
// EachResultF 与 EachResult 的功能相同,但是 abort 被默认为 false
|
||||
func EachResultF[K comparable, V any, R any](m map[K]V, iterator func(i int, key K, item V) (R, bool)) []R {
|
||||
return EachResult(false, m, iterator)
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package hash
|
||||
|
||||
// Filter 根据特定的表达式过滤哈希表成员
|
||||
// - reserve: 是否保留符合条件的成员
|
||||
// - m: 待过滤的哈希表
|
||||
// - expression: 过滤表达式
|
||||
//
|
||||
// 这个函数的作用是遍历输入哈希表 m,然后根据 expression 函数的返回值来决定是否保留每个元素。具体来说
|
||||
// - 如果 expression 返回 true 并且 reserve 也是 true,那么元素会被保留
|
||||
// - 如果 expression 返回 false 并且 reserve 是 false,那么元素也会被保留
|
||||
//
|
||||
// 该没有创建新的内存空间或进行元素复制,所以整个操作相当高效。同时,由于 m 和 map 实际上共享底层的数组,因此这个函数会改变传入的 map。如果不希望改变原哈希表,需要在函数调用之前手动复制一份或者使用 FilterCopy 函数。
|
||||
func Filter[K comparable, V any](reserve bool, m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
if len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
|
||||
for key, value := range m {
|
||||
if !expression(key, value) {
|
||||
delete(m, key)
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// FilterT 与 Filter 的功能相同,但是 reserve 被默认为 true
|
||||
func FilterT[K comparable, V any](m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
return Filter(true, m, expression)
|
||||
}
|
||||
|
||||
// FilterF 与 Filter 的功能相同,但是 reserve 被默认为 false
|
||||
func FilterF[K comparable, V any](m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
return Filter(false, m, expression)
|
||||
}
|
||||
|
||||
// FilterCopy 与 Filter 的功能相同,但是不会改变原哈希表,而是返回一个新的哈希表
|
||||
func FilterCopy[K comparable, V any](reserve bool, m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
var res = map[K]V{}
|
||||
for key, value := range m {
|
||||
if expression(key, value) {
|
||||
res[key] = value
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// FilterTCopy 与 FilterCopy 的功能相同,但是 reserve 被默认为 true
|
||||
func FilterTCopy[K comparable, V any](m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
return FilterCopy(true, m, expression)
|
||||
}
|
||||
|
||||
// FilterFCopy 与 FilterCopy 的功能相同,但是 reserve 被默认为 false
|
||||
func FilterFCopy[K comparable, V any](m map[K]V, expression func(key K, value V) bool) map[K]V {
|
||||
return FilterCopy(false, m, expression)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package slice
|
||||
|
||||
// Chunk 返回分块后的切片
|
||||
func Chunk[T any](collection []T, size int) [][]T {
|
||||
if len(collection) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if size < 1 {
|
||||
panic("size must be greater than 0")
|
||||
}
|
||||
|
||||
result := make([][]T, 0, (len(collection)+size-1)/size)
|
||||
for size < len(collection) {
|
||||
collection, result = collection[size:], append(result, collection[0:size])
|
||||
}
|
||||
return append(result, collection)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package slice
|
||||
|
||||
// Drop 从切片中删除指定数量的元素
|
||||
// - start: 起始位置
|
||||
// - n: 删除的元素数量
|
||||
// - slice: 待删除元素的切片
|
||||
//
|
||||
// 关于 start 的取值:
|
||||
// - 当 start < 0 时,start 将会从右至左计数,即 -1 表示最后一个元素,-2 表示倒数第二个元素,以此类推
|
||||
func Drop[V any](start, n int, slice []V) []V {
|
||||
var s = make([]V, len(slice))
|
||||
copy(s, slice)
|
||||
if start < 0 {
|
||||
start = len(s) + start - n + 1
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
}
|
||||
|
||||
end := start + n
|
||||
if end > len(s) {
|
||||
end = len(s)
|
||||
}
|
||||
|
||||
return append(s[:start], s[end:]...)
|
||||
}
|
||||
|
||||
// DropBy 从切片中删除指定的元素
|
||||
// - slice: 待删除元素的切片
|
||||
func DropBy[V any](slice []V, fn func(index int, value V) bool) []V {
|
||||
var s = make([]V, len(slice))
|
||||
copy(s, slice)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if fn(i, s[i]) {
|
||||
s = append(s[:i], s[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package slice_test
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/utils/slice"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDrop(t *testing.T) {
|
||||
s := []int{1, 2, 3, 4, 5}
|
||||
t.Log(s, slice.Drop(1, 3, s))
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package slice
|
||||
|
||||
// Each 根据传入的 abort 遍历 slice,如果 iterator 返回值与 abort 相同,则停止遍历
|
||||
func Each[V any](abort bool, slice []V, iterator func(index int, item V) bool) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
if iterator(i, slice[i]) == abort {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EachT 与 Each 的功能相同,但是 abort 被默认为 true
|
||||
func EachT[V any](slice []V, iterator func(index int, item V) bool) {
|
||||
Each(true, slice, iterator)
|
||||
}
|
||||
|
||||
// EachF 与 Each 的功能相同,但是 abort 被默认为 false
|
||||
func EachF[V any](slice []V, iterator func(index int, item V) bool) {
|
||||
Each(false, slice, iterator)
|
||||
}
|
||||
|
||||
// EachReverse 根据传入的 abort 从后往前遍历 slice,如果 iterator 返回值与 abort 相同,则停止遍历
|
||||
func EachReverse[V any](abort bool, slice []V, iterator func(index int, item V) bool) {
|
||||
for i := len(slice) - 1; i >= 0; i-- {
|
||||
if iterator(i, slice[i]) == abort {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EachReverseT 与 EachReverse 的功能相同,但是 abort 被默认为 true
|
||||
func EachReverseT[V any](slice []V, iterator func(index int, item V) bool) {
|
||||
EachReverse(true, slice, iterator)
|
||||
}
|
||||
|
||||
// EachReverseF 与 EachReverse 的功能相同,但是 abort 被默认为 false
|
||||
func EachReverseF[V any](slice []V, iterator func(index int, item V) bool) {
|
||||
EachReverse(false, slice, iterator)
|
||||
}
|
||||
|
||||
// EachResult 根据传入的 abort 遍历 slice,得到遍历的结果,如果 iterator 返回值中的 bool 值与 abort 相同,则停止遍历,并返回当前已积累的结果
|
||||
func EachResult[V any, R any](abort bool, slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
var result []R
|
||||
for i := 0; i < len(slice); i++ {
|
||||
r, ok := iterator(i, slice[i])
|
||||
result = append(result, r)
|
||||
if ok == abort {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EachResultT 与 EachResult 的功能相同,但是 abort 被默认为 true
|
||||
func EachResultT[V any, R any](slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
return EachResult(true, slice, iterator)
|
||||
}
|
||||
|
||||
// EachResultF 与 EachResult 的功能相同,但是 abort 被默认为 false
|
||||
func EachResultF[V any, R any](slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
return EachResult(false, slice, iterator)
|
||||
}
|
||||
|
||||
// EachResultReverse 根据传入的 abort 从后往前遍历 slice,得到遍历的结果,如果 iterator 返回值中的 bool 值与 abort 相同,则停止遍历,并返回当前已积累的结果
|
||||
func EachResultReverse[V any, R any](abort bool, slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
var result []R
|
||||
for i := len(slice) - 1; i >= 0; i-- {
|
||||
r, ok := iterator(i, slice[i])
|
||||
result = append(result, r)
|
||||
if ok == abort {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EachResultReverseT 与 EachResultReverse 的功能相同,但是 abort 被默认为 true
|
||||
func EachResultReverseT[V any, R any](slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
return EachResultReverse(true, slice, iterator)
|
||||
}
|
||||
|
||||
// EachResultReverseF 与 EachResultReverse 的功能相同,但是 abort 被默认为 false
|
||||
func EachResultReverseF[V any, R any](slice []V, iterator func(index int, item V) (R, bool)) []R {
|
||||
return EachResultReverse(false, slice, iterator)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package slice
|
||||
|
||||
// FillBy 用指定的值填充切片
|
||||
// - slice: 待填充的切片
|
||||
func FillBy[V any](slice []V, fn func(index int, value V) V) []V {
|
||||
for i, v := range slice {
|
||||
slice[i] = fn(i, v)
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// FillByCopy 与 FillBy 的功能相同,但是不会改变原切片,而是返回一个新的切片
|
||||
func FillByCopy[V any](slice []V, fn func(index int, value V) V) []V {
|
||||
var s = make([]V, len(slice))
|
||||
copy(s, slice)
|
||||
return FillBy(s, fn)
|
||||
}
|
||||
|
||||
// FillUntil 用指定的值填充切片,如果 fn 返回的 bool 值与 abort 相同,则停止填充
|
||||
// - abort: 填充中止条件
|
||||
// - slice: 待填充的切片
|
||||
func FillUntil[V any](abort bool, slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
for i, v := range slice {
|
||||
if value, b := fn(i, v); b == abort {
|
||||
break
|
||||
} else {
|
||||
slice[i] = value
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// FillUntilCopy 与 FillUntil 的功能相同,但不会改变原切片,而是返回一个新的切片
|
||||
func FillUntilCopy[V any](abort bool, slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
var s = make([]V, len(slice))
|
||||
copy(s, slice)
|
||||
return FillUntil(abort, s, fn)
|
||||
}
|
||||
|
||||
// FillUntilT 是 FillUntil 的简化版本,其中 abort 参数为 true
|
||||
func FillUntilT[V any](slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
return FillUntil(true, slice, fn)
|
||||
}
|
||||
|
||||
// FillUntilF 是 FillUntil 的简化版本,其中 abort 参数为 false
|
||||
func FillUntilF[V any](slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
return FillUntil(false, slice, fn)
|
||||
}
|
||||
|
||||
// FillUntilTCopy 是 FillUntilCopy 的简化版本,其中 abort 参数为 true
|
||||
func FillUntilTCopy[V any](slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
return FillUntilCopy(true, slice, fn)
|
||||
}
|
||||
|
||||
// FillUntilFCopy 是 FillUntilCopy 的简化版本,其中 abort 参数为 false
|
||||
func FillUntilFCopy[V any](slice []V, fn func(index int, value V) (V, bool)) []V {
|
||||
return FillUntilCopy(false, slice, fn)
|
||||
}
|
|
@ -53,12 +53,12 @@ func FilterCopy[V any](reserve bool, slice []V, expression func(index int, item
|
|||
return Filter(reserve, s, expression)
|
||||
}
|
||||
|
||||
// FilterCopyT 与 FilterCopy 的功能相同,但是 reserve 被默认为 true
|
||||
func FilterCopyT[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||
// FilterTCopy 与 FilterCopy 的功能相同,但是 reserve 被默认为 true
|
||||
func FilterTCopy[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 {
|
||||
// FilterFCopy 与 FilterCopy 的功能相同,但是 reserve 被默认为 false
|
||||
func FilterFCopy[V any](slice []V, expression func(index int, item V) bool) []V {
|
||||
return FilterCopy(false, slice, expression)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package slice
|
||||
|
||||
// GroupBy 返回分组后的切片
|
||||
func GroupBy[T any, K comparable](collection []T, fn func(T) K) map[K][]T {
|
||||
if len(collection) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make(map[K][]T, len(collection))
|
||||
|
||||
for _, item := range collection {
|
||||
key := fn(item)
|
||||
result[key] = append(result[key], item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package slice
|
||||
|
||||
import "math/rand"
|
||||
|
||||
// Shuffle 随机打乱切片
|
||||
// - 该函数会改变传入的切片,如果不希望改变原切片,需要在函数调用之前手动复制一份或者使用 ShuffleCopy 函数
|
||||
func Shuffle[T any](collection []T) []T {
|
||||
rand.Shuffle(len(collection), func(i, j int) {
|
||||
collection[i], collection[j] = collection[j], collection[i]
|
||||
})
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
// ShuffleCopy 返回随机打乱后的切片
|
||||
// - 该函数不会改变原切片
|
||||
func ShuffleCopy[T any](collection []T) []T {
|
||||
if len(collection) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]T, len(collection))
|
||||
perm := rand.Perm(len(collection))
|
||||
|
||||
for i, randIndex := range perm {
|
||||
result[i] = collection[randIndex]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package slice
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
|
@ -111,14 +110,6 @@ func Reverse[V any](slice []V) {
|
|||
}
|
||||
}
|
||||
|
||||
// Shuffle 随机打乱数组
|
||||
func Shuffle[V any](slice []V) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
j := rand.Intn(len(slice))
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Distinct 去重
|
||||
func Distinct[V any](slice []V) []V {
|
||||
var result []V
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package slice
|
||||
|
||||
// Unique 返回去重后的切片
|
||||
func Unique[T comparable](collection []T) []T {
|
||||
if len(collection) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]T, 0, len(collection))
|
||||
seen := make(map[T]struct{}, len(collection))
|
||||
|
||||
for _, item := range collection {
|
||||
if _, ok := seen[item]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqueBy 返回去重后的切片
|
||||
func UniqueBy[T any](collection []T, fn func(T) any) []T {
|
||||
if len(collection) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]T, 0, len(collection))
|
||||
seen := make(map[any]struct{}, len(collection))
|
||||
|
||||
for _, item := range collection {
|
||||
key := fn(item)
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[key] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
Loading…
Reference in New Issue