Skip to content

Commit

Permalink
feat: 新增大量 slice 包和 hash 包的辅助函数
Browse files Browse the repository at this point in the history
  • Loading branch information
kercylan98 committed Sep 8, 2023
1 parent 5ab9902 commit d772409
Show file tree
Hide file tree
Showing 14 changed files with 493 additions and 13 deletions.
27 changes: 27 additions & 0 deletions utils/hash/chunk.go
Original file line number Diff line number Diff line change
@@ -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
}
56 changes: 56 additions & 0 deletions utils/hash/drop.go
Original file line number Diff line number Diff line change
@@ -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
}
47 changes: 47 additions & 0 deletions utils/hash/each.go
Original file line number Diff line number Diff line change
@@ -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)
}
56 changes: 56 additions & 0 deletions utils/hash/filter.go
Original file line number Diff line number Diff line change
@@ -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)
}
18 changes: 18 additions & 0 deletions utils/slice/chunk.go
Original file line number Diff line number Diff line change
@@ -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)
}
40 changes: 40 additions & 0 deletions utils/slice/drop.go
Original file line number Diff line number Diff line change
@@ -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
}
11 changes: 11 additions & 0 deletions utils/slice/drop_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
85 changes: 85 additions & 0 deletions utils/slice/each.go
Original file line number Diff line number Diff line change
@@ -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)
}
Loading

0 comments on commit d772409

Please sign in to comment.