diff --git a/helper/maps/map.go b/helper/maps/map.go index 5fe48c8..54557b0 100644 --- a/helper/maps/map.go +++ b/helper/maps/map.go @@ -55,3 +55,15 @@ func Reduce[T, V any, K comparable](m map[K]V, fn func(K, V, T) T, r T) T { } return r } + +func Replace[K comparable, V any](m map[K]V, mm ...map[K]V) map[K]V { + for _, n := range mm { + for k, v := range n { + _, ok := m[k] + if ok { + m[k] = v + } + } + } + return m +} diff --git a/helper/number/number.go b/helper/number/number.go index c386a2f..fc4fa0c 100644 --- a/helper/number/number.go +++ b/helper/number/number.go @@ -10,6 +10,10 @@ type IntNumber interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 } +type Number interface { + IntNumber | ~float64 | ~float32 +} + func Range[T IntNumber](start, end, step T) []T { if step == 0 { panic("step can't be 0") @@ -29,12 +33,13 @@ func Range[T IntNumber](start, end, step T) []T { return r } +// Rand 都为闭区间 [start,end] func Rand[T IntNumber](start, end T) T { end++ return T(rand.Int63n(int64(end-start))) + start } -func Min[T IntNumber | ~float64 | ~float32](a ...T) T { +func Min[T Number](a ...T) T { min := a[0] for _, t := range a { if min > t { @@ -44,7 +49,7 @@ func Min[T IntNumber | ~float64 | ~float32](a ...T) T { return min } -func Max[T IntNumber | ~float64 | ~float32](a ...T) T { +func Max[T Number](a ...T) T { max := a[0] for _, t := range a { if max < t { @@ -54,7 +59,7 @@ func Max[T IntNumber | ~float64 | ~float32](a ...T) T { return max } -func Sum[T IntNumber | ~float64 | ~float32](a ...T) T { +func Sum[T Number](a ...T) T { s := T(0) for _, t := range a { s += t @@ -62,6 +67,17 @@ func Sum[T IntNumber | ~float64 | ~float32](a ...T) T { return s } -func ToString[T IntNumber | ~float64 | ~float32](n T) string { +func Add[T Number](i, j T) T { + return i + j +} + +func ToString[T Number](n T) string { return fmt.Sprintf("%v", n) } + +func Abs[T Number](n T) T { + if n >= 0 { + return n + } + return -n +} diff --git a/helper/slice/slice.go b/helper/slice/slice.go index 8c7caff..4c5c2ca 100644 --- a/helper/slice/slice.go +++ b/helper/slice/slice.go @@ -1,6 +1,9 @@ package slice -import "github.com/fthvgb1/wp-go/helper" +import ( + "github.com/fthvgb1/wp-go/helper" + "github.com/fthvgb1/wp-go/helper/number" +) func Map[T, R any](arr []T, fn func(T) R) []R { r := make([]R, 0, len(arr)) @@ -190,3 +193,63 @@ func GroupBy[K comparable, T, V any](a []T, fn func(T) (K, V)) map[K][]V { func ToAnySlice[T any](a []T) []any { return Map(a, helper.ToAny[T]) } + +func Fill[T any](start, len int, v T) []T { + r := make([]T, start+len) + for i := 0; i < len; i++ { + r[start+i] = v + } + return r +} + +// Pad returns a copy of the array padded to size specified by length with value. If length is positive then the array is padded on the right, if it's negative then on the left. If the absolute value of length is less than or equal to the length of the array then no padding takes place. +func Pad[T any](a []T, length int, v T) []T { + l := len(a) + if length > l { + return append(a, Fill(0, length-l, v)...) + } else if length < 0 && -length > l-1 { + return append(Fill(0, -length-2, v), a...) + } + return a +} + +func Pop[T any](a *[]T) T { + arr := *a + v := arr[len(arr)-1] + + *a = append(arr[:len(arr)-1]) + return v +} + +func Rand[T any](a []T) (int, T) { + i := number.Rand(0, len(a)-1) + return i, a[i] +} + +func RandPop[T any](a *[]T) (T, int) { + arr := *a + if len(arr) == 0 { + var r T + return r, 0 + } + i := number.Rand(0, len(arr)-1) + v := arr[i] + if len(arr)-1 == i { + *a = append(arr[:i]) + } else { + *a = append(arr[:i], arr[i+1:]...) + } + return v, len(arr) - 1 +} + +func Shift[T any](a *[]T) (T, int) { + arr := *a + l := len(arr) + if l > 0 { + v := arr[0] + *a = arr[1:] + return v, l - 1 + } + var r T + return r, 0 +} diff --git a/helper/slice/slice_test.go b/helper/slice/slice_test.go index 9cc3a86..71dd85b 100644 --- a/helper/slice/slice_test.go +++ b/helper/slice/slice_test.go @@ -651,3 +651,192 @@ func TestWalk(t *testing.T) { }) } } + +func TestFill(t *testing.T) { + type args[T int] struct { + start int + len int + v T + } + type testCase[T int] struct { + name string + args args[T] + want []T + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + start: 2, + len: 3, + v: 1, + }, + want: []int{0, 0, 1, 1, 1}, + }, { + name: "t2", + args: args[int]{ + start: 0, + len: 3, + v: 2, + }, + want: []int{2, 2, 2}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Fill(tt.args.start, tt.args.len, tt.args.v); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Fill() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestPad(t *testing.T) { + type args[T int] struct { + a []T + length int + v T + } + type testCase[T int] struct { + name string + args args[T] + want []T + } + tests := []testCase[int]{ + { + name: "length >0", + args: args[int]{ + a: []int{1, 2}, + length: 5, + v: 10, + }, + want: []int{1, 2, 10, 10, 10}, + }, + { + name: "length <0", + args: args[int]{ + a: []int{1, 2}, + length: -5, + v: 10, + }, + want: []int{10, 10, 10, 1, 2}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Pad(tt.args.a, tt.args.length, tt.args.v); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Pad() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestPop(t *testing.T) { + type args[T int] struct { + a *[]T + } + type testCase[T int] struct { + name string + args args[T] + want T + } + a := number.Range(1, 10, 1) + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + a: &a, + }, + want: 10, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Pop(tt.args.a); !reflect.DeepEqual(got, tt.want) && !reflect.DeepEqual(a, number.Range(1, 9, 1)) { + t.Errorf("Pop() = %v, want %v", got, tt.want) + } + fmt.Println(a) + }) + } +} + +func TestRand(t *testing.T) { + type args[T int] struct { + a []T + } + type testCase[T int] struct { + name string + args args[T] + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + number.Range(1, 5, 1), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < 50; i++ { + got, got1 := Rand(tt.args.a) + fmt.Println(got, got1) + } + }) + } +} + +func TestRandPop(t *testing.T) { + type args[T int] struct { + a *[]T + } + type testCase[T int] struct { + name string + args args[T] + want T + } + a := number.Range(1, 10, 1) + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + a: &a, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < 11; i++ { + got, l := RandPop(tt.args.a) + fmt.Println(got, l, a) + } + }) + } +} + +func TestShift(t *testing.T) { + type args[T int] struct { + a *[]T + } + type testCase[T int] struct { + name string + args args[T] + want T + want1 int + } + a := number.Range(1, 10, 1) + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{&a}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < 11; i++ { + got, got1 := Shift(tt.args.a) + fmt.Println(got, got1) + } + }) + } +} diff --git a/helper/slice/slices.go b/helper/slice/slices.go new file mode 100644 index 0000000..5c95c9d --- /dev/null +++ b/helper/slice/slices.go @@ -0,0 +1,35 @@ +package slice + +func Splice[T any](a *[]T, offset, length int, replacement []T) []T { + arr := *a + l := len(arr) + if length < 0 { + panic("length must > 0") + } + if offset >= 0 { + if offset+length > l { + return nil + } else if l > offset && l < offset+length { + v := arr[offset:l] + *a = append(arr[:offset], replacement...) + return v + } else if offset+length <= l { + v := append([]T{}, arr[offset:offset+length]...) + *a = append(arr[:offset], append(replacement, arr[offset+length:]...)...) + return v + } + } else { + if -offset > l { + return nil + } else if -offset <= l && l+offset+length < l { + v := append([]T{}, arr[l+offset:l+offset+length]...) + *a = append(arr[:l+offset], append(replacement, arr[l+offset+length:]...)...) + return v + } else if -offset <= l && l+offset+length >= l { + v := append([]T{}, arr[l+offset:]...) + *a = append(arr[:l+offset], replacement...) + return v + } + } + return nil +} diff --git a/helper/slice/slices_test.go b/helper/slice/slices_test.go new file mode 100644 index 0000000..e7f19bd --- /dev/null +++ b/helper/slice/slices_test.go @@ -0,0 +1,79 @@ +package slice + +import ( + "fmt" + "github.com/fthvgb1/wp-go/helper/number" + "reflect" + "testing" +) + +func TestSplice(t *testing.T) { + type args[T int] struct { + a *[]T + offset int + length int + replacement []T + } + type testCase[T int] struct { + name string + args args[T] + want []T + } + a := number.Range(1, 10, 1) + b := number.Range(1, 10, 1) + c := number.Range(1, 10, 1) + d := number.Range(1, 10, 1) + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + a: &a, + offset: 3, + length: 2, + replacement: nil, + }, + want: []int{4, 5}, + }, + { + name: "t2", + args: args[int]{ + a: &b, + offset: 3, + length: 2, + replacement: []int{11, 12, 15}, + }, + want: []int{4, 5}, + }, + { + name: "t3", + args: args[int]{ + a: &c, + offset: -1, + length: 2, + replacement: nil, //[]int{11, 12, 15}, + }, + want: []int{10}, + }, + { + name: "t4", + args: args[int]{ + a: &d, + offset: -3, + length: 5, + replacement: []int{11, 12, 15}, + }, + want: []int{8, 9, 10}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Splice(tt.args.a, tt.args.offset, tt.args.length, tt.args.replacement); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Splice() = %v, want %v", got, tt.want) + } + }) + } + fmt.Println(a) + fmt.Println(b) + fmt.Println(c) + fmt.Println(d) +}