feat: 新增 steram 包,支持 map 和 slice 的链式操作
This commit is contained in:
parent
8f9589df42
commit
10fcb54322
|
@ -2,7 +2,7 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronization"
|
"github.com/kercylan98/minotaur/utils/asynchronous"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -12,7 +12,7 @@ import (
|
||||||
func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...RoomOption[PlayerID, Player]) *Room[PlayerID, Player] {
|
func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...RoomOption[PlayerID, Player]) *Room[PlayerID, Player] {
|
||||||
room := &Room[PlayerID, Player]{
|
room := &Room[PlayerID, Player]{
|
||||||
guid: guid,
|
guid: guid,
|
||||||
players: asynchronization.NewMap[PlayerID, Player](),
|
players: asynchronous.NewMap[PlayerID, Player](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(room)
|
option(room)
|
||||||
|
|
|
@ -2,7 +2,7 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronization"
|
"github.com/kercylan98/minotaur/utils/asynchronous"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
"github.com/kercylan98/minotaur/utils/slice"
|
"github.com/kercylan98/minotaur/utils/slice"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -12,7 +12,7 @@ import (
|
||||||
func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player], options ...RoomSeatOption[PlayerID, Player]) *RoomSeat[PlayerID, Player] {
|
func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player], options ...RoomSeatOption[PlayerID, Player]) *RoomSeat[PlayerID, Player] {
|
||||||
roomSeat := &RoomSeat[PlayerID, Player]{
|
roomSeat := &RoomSeat[PlayerID, Player]{
|
||||||
Room: room,
|
Room: room,
|
||||||
seatPS: asynchronization.NewMap[PlayerID, int](),
|
seatPS: asynchronous.NewMap[PlayerID, int](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(roomSeat)
|
option(roomSeat)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package report
|
package report
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronization"
|
"github.com/kercylan98/minotaur/utils/asynchronous"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ import (
|
||||||
func NewDataBuried[DataID comparable, Data any](name string, hitLogic HitLogic[Data], options ...DataBuriedOption[DataID, Data]) *DataBuried[DataID, Data] {
|
func NewDataBuried[DataID comparable, Data any](name string, hitLogic HitLogic[Data], options ...DataBuriedOption[DataID, Data]) *DataBuried[DataID, Data] {
|
||||||
buried := &DataBuried[DataID, Data]{
|
buried := &DataBuried[DataID, Data]{
|
||||||
name: name,
|
name: name,
|
||||||
data: asynchronization.NewMap[DataID, Data](),
|
data: asynchronous.NewMap[DataID, Data](),
|
||||||
hitLogic: hitLogic,
|
hitLogic: hitLogic,
|
||||||
}
|
}
|
||||||
buried.setData = func(id DataID, data Data) {
|
buried.setData = func(id DataID, data Data) {
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package asynchronization
|
package asynchronous
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewMap[Key comparable, value any]() *Map[Key, value] {
|
func NewMap[Key comparable, Value any](options ...MapOption[Key, Value]) *Map[Key, Value] {
|
||||||
return &Map[Key, value]{
|
m := &Map[Key, Value]{
|
||||||
data: make(map[Key]value),
|
data: make(map[Key]Value),
|
||||||
}
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(m)
|
||||||
|
}
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map 非并发安全的字典数据结构
|
// Map 非并发安全的字典数据结构
|
|
@ -0,0 +1,10 @@
|
||||||
|
package asynchronous
|
||||||
|
|
||||||
|
type MapOption[Key comparable, Value any] func(m *Map[Key, Value])
|
||||||
|
|
||||||
|
// WithMapSource 通过传入的 map 初始化
|
||||||
|
func WithMapSource[Key comparable, Value any](source map[Key]Value) MapOption[Key, Value] {
|
||||||
|
return func(m *Map[Key, Value]) {
|
||||||
|
m.data = source
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,3 +37,8 @@ func IntN(n int) int {
|
||||||
}
|
}
|
||||||
return rand.Intn(n)
|
return rand.Intn(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool 返回一个随机的布尔值
|
||||||
|
func Bool() bool {
|
||||||
|
return rand.Intn(2) == 1
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package slice
|
package slice
|
||||||
|
|
||||||
import "math/rand"
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
// Del 删除特定索引的元素
|
// Del 删除特定索引的元素
|
||||||
func Del[V any](slice *[]V, index int) {
|
func Del[V any](slice *[]V, index int) {
|
||||||
|
@ -98,6 +101,24 @@ func Shuffle[V any](slice []V) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distinct 去重
|
||||||
|
func Distinct[V any](slice []V) []V {
|
||||||
|
var result []V
|
||||||
|
for i := range slice {
|
||||||
|
flag := true
|
||||||
|
for j := range result {
|
||||||
|
if reflect.DeepEqual(slice[i], result[j]) {
|
||||||
|
flag = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flag {
|
||||||
|
result = append(result, slice[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// Swap 交换数组中的两个元素
|
// Swap 交换数组中的两个元素
|
||||||
func Swap[V any](slice []V, i, j int) {
|
func Swap[V any](slice []V, i, j int) {
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
@ -146,7 +167,7 @@ func GetEndPart[V any](slice []V, n int) []V {
|
||||||
return slice[len(slice)-n:]
|
return slice[len(slice)-n:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPart 获取数组的部分元素
|
// GetPart 获取指定区间的元素
|
||||||
func GetPart[V any](slice []V, start, end int) []V {
|
func GetPart[V any](slice []V, start, end int) []V {
|
||||||
if start < 0 {
|
if start < 0 {
|
||||||
start = 0
|
start = 0
|
||||||
|
@ -156,3 +177,23 @@ func GetPart[V any](slice []V, start, end int) []V {
|
||||||
}
|
}
|
||||||
return slice[start:end]
|
return slice[start:end]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contains 判断数组是否包含某个元素
|
||||||
|
func Contains[V comparable](slice []V, value V) bool {
|
||||||
|
for _, v := range slice {
|
||||||
|
if v == value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsAny 判断数组是否包含某个元素
|
||||||
|
func ContainsAny[V any](slice []V, values V) bool {
|
||||||
|
for _, v := range slice {
|
||||||
|
if reflect.DeepEqual(v, values) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/asynchronous"
|
||||||
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
|
"github.com/kercylan98/minotaur/utils/synchronization"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithMap 使用传入的 map 执行链式操作
|
||||||
|
// - 该函数将会直接影响到传入的 map
|
||||||
|
func WithMap[K comparable, V any](m map[K]V) Map[K, V] {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMapCopy 使用传入的 map 执行链式操作
|
||||||
|
// - 该函数不会影响到传入的 map
|
||||||
|
func WithMapCopy[K comparable, V any](m map[K]V) Map[K, V] {
|
||||||
|
return hash.Copy(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHashMap 使用传入的 map 执行链式操作
|
||||||
|
func WithHashMap[K comparable, V any](m hash.Map[K, V]) Map[K, V] {
|
||||||
|
return m.Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map 提供了 map 的链式操作
|
||||||
|
type Map[K comparable, V any] map[K]V
|
||||||
|
|
||||||
|
// Set 设置一个值
|
||||||
|
func (slf Map[K, V]) Set(key K, value V) Map[K, V] {
|
||||||
|
slf[key] = value
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除一个值
|
||||||
|
func (slf Map[K, V]) Delete(key K) Map[K, V] {
|
||||||
|
delete(slf, key)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter 过滤 handle 返回 false 的元素
|
||||||
|
func (slf Map[K, V]) Filter(handle func(key K, value V) bool) Map[K, V] {
|
||||||
|
for k, v := range slf {
|
||||||
|
if !handle(k, v) {
|
||||||
|
delete(slf, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterKey 过滤特定的 key
|
||||||
|
func (slf Map[K, V]) FilterKey(keys ...K) Map[K, V] {
|
||||||
|
for _, key := range keys {
|
||||||
|
delete(slf, key)
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterValue 过滤特定的 value
|
||||||
|
func (slf Map[K, V]) FilterValue(values ...V) Map[K, V] {
|
||||||
|
for k, v := range slf {
|
||||||
|
for _, value := range values {
|
||||||
|
if reflect.DeepEqual(v, value) {
|
||||||
|
delete(slf, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomKeep 随机保留 n 个元素
|
||||||
|
func (slf Map[K, V]) RandomKeep(n int) Map[K, V] {
|
||||||
|
length := len(slf)
|
||||||
|
if n >= length {
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
for k := range slf {
|
||||||
|
if n > 0 {
|
||||||
|
n--
|
||||||
|
} else {
|
||||||
|
delete(slf, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomDelete 随机删除 n 个元素
|
||||||
|
func (slf Map[K, V]) RandomDelete(n int) Map[K, V] {
|
||||||
|
var count int
|
||||||
|
for k := range slf {
|
||||||
|
if count < n {
|
||||||
|
count++
|
||||||
|
delete(slf, k)
|
||||||
|
} else {
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomReplace 将 values 覆盖到当前的 map 中
|
||||||
|
// - 如果 values 的长度大于当前 map 的长度,则只会覆盖当前 map 的长度
|
||||||
|
func (slf Map[K, V]) RandomReplace(values ...V) Map[K, V] {
|
||||||
|
var record []K
|
||||||
|
var valuesLen = len(values)
|
||||||
|
for k := range slf {
|
||||||
|
record = append(record, k)
|
||||||
|
if len(record) >= valuesLen {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, k := range record {
|
||||||
|
slf.Set(k, values[i])
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distinct 去重,如果 handle 返回 true,则认为是重复的元素
|
||||||
|
func (slf Map[K, V]) Distinct(handle func(key K, value V) bool) Map[K, V] {
|
||||||
|
for k, v := range slf {
|
||||||
|
if handle(k, v) {
|
||||||
|
delete(slf, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range 遍历当前 Map, handle 返回 false 则停止遍历
|
||||||
|
func (slf Map[K, V]) Range(handle func(key K, value V) bool) Map[K, V] {
|
||||||
|
for k, v := range slf {
|
||||||
|
if !handle(k, v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueOr 当 key 不存在时,设置一个默认值
|
||||||
|
func (slf Map[K, V]) ValueOr(key K, value V) Map[K, V] {
|
||||||
|
if _, ok := slf[key]; !ok {
|
||||||
|
slf[key] = value
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValueOr 当 key 不存在时,返回一个默认值
|
||||||
|
func (slf Map[K, V]) GetValueOr(key K, value V) V {
|
||||||
|
if v, ok := slf[key]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear 清空当前 Map
|
||||||
|
func (slf Map[K, V]) Clear() Map[K, V] {
|
||||||
|
for k := range slf {
|
||||||
|
delete(slf, k)
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge 合并多个 Map
|
||||||
|
func (slf Map[K, V]) Merge(maps ...map[K]V) Map[K, V] {
|
||||||
|
for _, m := range maps {
|
||||||
|
for k, v := range m {
|
||||||
|
slf[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSliceStream 将当前 Map stream 转换为 Slice stream
|
||||||
|
func (slf Map[K, V]) ToSliceStream() Slice[V] {
|
||||||
|
return hash.ToSlice(slf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSliceStreamWithKey 将当前 Map stream 转换为 Slice stream,key 为 Slice 的元素
|
||||||
|
func (slf Map[K, V]) ToSliceStreamWithKey() Slice[K] {
|
||||||
|
return hash.KeyToSlice(slf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSyncMap 将当前 Map 转换为 synchronization.Map
|
||||||
|
func (slf Map[K, V]) ToSyncMap() *synchronization.Map[K, V] {
|
||||||
|
return synchronization.NewMap[K, V](synchronization.WithMapSource(slf))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToAsyncMap 将当前 Map 转换为 asynchronous.Map
|
||||||
|
func (slf Map[K, V]) ToAsyncMap() *asynchronous.Map[K, V] {
|
||||||
|
return asynchronous.NewMap[K, V](asynchronous.WithMapSource(slf))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMap 将当前 Map 转换为 map
|
||||||
|
func (slf Map[K, V]) ToMap() map[K]V {
|
||||||
|
return slf
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package stream_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kercylan98/minotaur/utils/stream"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleWithMap() {
|
||||||
|
m := stream.WithMap(map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "d"}).Filter(func(key int, value string) bool {
|
||||||
|
return key > 3
|
||||||
|
})
|
||||||
|
fmt.Println(len(m))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWithMapCopy() {
|
||||||
|
m := stream.WithMapCopy(map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "d"}).Filter(func(key int, value string) bool {
|
||||||
|
return key > 3
|
||||||
|
})
|
||||||
|
fmt.Println(len(m))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 2
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package stream_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/stream"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initMap() map[int]int {
|
||||||
|
return map[int]int{
|
||||||
|
1: 100,
|
||||||
|
2: 200,
|
||||||
|
3: 300,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMap(t *testing.T) {
|
||||||
|
Convey("TestWithMap", t, func() {
|
||||||
|
var s = initMap()
|
||||||
|
var m = stream.WithMap(s).RandomDelete(1)
|
||||||
|
So(m, ShouldNotBeNil)
|
||||||
|
So(len(s), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMapCopy(t *testing.T) {
|
||||||
|
Convey("TestWithMapCopy", t, func() {
|
||||||
|
var s = initMap()
|
||||||
|
var m = stream.WithMapCopy(s).RandomDelete(1)
|
||||||
|
So(m, ShouldNotBeNil)
|
||||||
|
So(len(s), ShouldEqual, 3)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_Set(t *testing.T) {
|
||||||
|
Convey("TestMap_Set", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).Set(4, 400)
|
||||||
|
So(m[4], ShouldEqual, 400)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_Filter(t *testing.T) {
|
||||||
|
Convey("TestMap_Filter", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).Filter(func(key int, value int) bool {
|
||||||
|
return key == 1
|
||||||
|
})
|
||||||
|
So(len(m), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_FilterKey(t *testing.T) {
|
||||||
|
Convey("TestMap_FilterKey", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).FilterKey(1)
|
||||||
|
So(len(m), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_FilterValue(t *testing.T) {
|
||||||
|
Convey("TestMap_FilterValue", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).FilterValue(100)
|
||||||
|
So(len(m), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_RandomKeep(t *testing.T) {
|
||||||
|
Convey("TestMap_RandomKeep", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).RandomKeep(1)
|
||||||
|
So(len(m), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_RandomDelete(t *testing.T) {
|
||||||
|
Convey("TestMap_RandomDelete", t, func() {
|
||||||
|
var m = stream.WithMap(initMap()).RandomDelete(1)
|
||||||
|
So(len(m), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap_Distinct(t *testing.T) {
|
||||||
|
Convey("TestMap_Distinct", t, func() {
|
||||||
|
var m = stream.WithMap(map[int]int{
|
||||||
|
1: 100,
|
||||||
|
2: 200,
|
||||||
|
3: 100,
|
||||||
|
}).Distinct(func(key int, value int) bool {
|
||||||
|
return value == 100
|
||||||
|
})
|
||||||
|
So(len(m), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
|
"github.com/kercylan98/minotaur/utils/slice"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithSlice 创建一个 Slice
|
||||||
|
// - 该函数不会影响到传入的 slice
|
||||||
|
func WithSlice[V any](values []V) Slice[V] {
|
||||||
|
return slice.Copy(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice 提供了 slice 的链式操作
|
||||||
|
type Slice[V any] []V
|
||||||
|
|
||||||
|
// Filter 过滤 handle 返回 false 的元素
|
||||||
|
func (slf Slice[V]) Filter(handle func(index int, value V) bool) Slice[V] {
|
||||||
|
var ns = make([]V, 0, len(slf))
|
||||||
|
for i, v := range slf {
|
||||||
|
if handle(i, v) {
|
||||||
|
ns = append(ns, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterValue 过滤特定的 value
|
||||||
|
func (slf Slice[V]) FilterValue(values ...V) Slice[V] {
|
||||||
|
return slf.Filter(func(index int, value V) bool {
|
||||||
|
for _, v := range values {
|
||||||
|
if reflect.DeepEqual(v, value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterIndex 过滤特定的 index
|
||||||
|
func (slf Slice[V]) FilterIndex(indexes ...int) Slice[V] {
|
||||||
|
return slf.Filter(func(index int, value V) bool {
|
||||||
|
return !slice.Contains(indexes, index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomKeep 随机保留 n 个元素
|
||||||
|
func (slf Slice[V]) RandomKeep(n int) Slice[V] {
|
||||||
|
length := len(slf)
|
||||||
|
if n >= length {
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
var hit = make([]int, length, length)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
hit[i] = 1
|
||||||
|
}
|
||||||
|
slice.Shuffle(hit)
|
||||||
|
var ns = make([]V, 0, n)
|
||||||
|
for i, v := range slf {
|
||||||
|
if hit[i] == 1 {
|
||||||
|
ns = append(ns, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomDelete 随机删除 n 个元素
|
||||||
|
func (slf Slice[V]) RandomDelete(n int) Slice[V] {
|
||||||
|
length := len(slf)
|
||||||
|
if n >= length {
|
||||||
|
return slf[:0]
|
||||||
|
}
|
||||||
|
var hit = make([]int, length, length)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
hit[i] = 1
|
||||||
|
}
|
||||||
|
slice.Shuffle(hit)
|
||||||
|
var ns = make([]V, 0, n)
|
||||||
|
for i, v := range slf {
|
||||||
|
if hit[i] == 0 {
|
||||||
|
ns = append(ns, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle 随机打乱
|
||||||
|
func (slf Slice[V]) Shuffle() Slice[V] {
|
||||||
|
slice.Shuffle(slf)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse 反转
|
||||||
|
func (slf Slice[V]) Reverse() Slice[V] {
|
||||||
|
slice.Reverse(slf)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear 清空
|
||||||
|
func (slf Slice[V]) Clear() Slice[V] {
|
||||||
|
return slf[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distinct 去重,如果 handle 返回 true 则认为是重复元素
|
||||||
|
func (slf Slice[V]) Distinct() Slice[V] {
|
||||||
|
return slice.Distinct(slf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge 合并
|
||||||
|
func (slf Slice[V]) Merge(values ...V) Slice[V] {
|
||||||
|
return append(slf, values...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStartPart 获取前 n 个元素
|
||||||
|
func (slf Slice[V]) GetStartPart(n int) Slice[V] {
|
||||||
|
return slf[:n]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEndPart 获取后 n 个元素
|
||||||
|
func (slf Slice[V]) GetEndPart(n int) Slice[V] {
|
||||||
|
return slice.GetEndPart(slf, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPart 获取指定区间的元素
|
||||||
|
func (slf Slice[V]) GetPart(start, end int) Slice[V] {
|
||||||
|
return slice.GetPart(slf, start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsHandle 如果包含指定的元素则执行 handle
|
||||||
|
func (slf Slice[V]) ContainsHandle(value V, handle func(slice Slice[V]) Slice[V]) Slice[V] {
|
||||||
|
if slice.ContainsAny(slf, value) {
|
||||||
|
return handle(slf)
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 设置指定位置的元素
|
||||||
|
func (slf Slice[V]) Set(index int, value V) Slice[V] {
|
||||||
|
slf[index] = value
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除指定位置的元素
|
||||||
|
func (slf Slice[V]) Delete(index int) Slice[V] {
|
||||||
|
return append(slf, slf[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMapStream 将当前的 Slice stream 转换为 Map stream
|
||||||
|
func (slf Slice[V]) ToMapStream() Map[int, V] {
|
||||||
|
return hash.ToMap(slf)
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package stream_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kercylan98/minotaur/utils/stream"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSlice_Filter(t *testing.T) {
|
||||||
|
Convey("TestSlice_Filter", t, func() {
|
||||||
|
d := []int{1, 2, 3, 4, 5}
|
||||||
|
var s = stream.WithSlice(d).Reverse()
|
||||||
|
fmt.Println(s)
|
||||||
|
fmt.Println(d)
|
||||||
|
So(len(s), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,10 +6,14 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewMap[Key comparable, value any]() *Map[Key, value] {
|
func NewMap[Key comparable, value any](options ...MapOption[Key, value]) *Map[Key, value] {
|
||||||
return &Map[Key, value]{
|
m := &Map[Key, value]{
|
||||||
data: make(map[Key]value),
|
data: make(map[Key]value),
|
||||||
}
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(m)
|
||||||
|
}
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map 并发安全的字典数据结构
|
// Map 并发安全的字典数据结构
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package synchronization
|
||||||
|
|
||||||
|
type MapOption[Key comparable, Value any] func(m *Map[Key, Value])
|
||||||
|
|
||||||
|
// WithMapSource 通过传入的 map 初始化
|
||||||
|
func WithMapSource[Key comparable, Value any](source map[Key]Value) MapOption[Key, Value] {
|
||||||
|
return func(m *Map[Key, Value]) {
|
||||||
|
m.data = source
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue