添加几个php的数组函数

This commit is contained in:
xing 2023-01-27 23:48:48 +08:00
parent 06e2f75000
commit 0832d679a3
6 changed files with 399 additions and 5 deletions

View File

@ -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 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
}

View File

@ -10,6 +10,10 @@ type IntNumber interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
} }
type Number interface {
IntNumber | ~float64 | ~float32
}
func Range[T IntNumber](start, end, step T) []T { func Range[T IntNumber](start, end, step T) []T {
if step == 0 { if step == 0 {
panic("step can't be 0") panic("step can't be 0")
@ -29,12 +33,13 @@ func Range[T IntNumber](start, end, step T) []T {
return r return r
} }
// Rand 都为闭区间 [start,end]
func Rand[T IntNumber](start, end T) T { func Rand[T IntNumber](start, end T) T {
end++ end++
return T(rand.Int63n(int64(end-start))) + start 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] min := a[0]
for _, t := range a { for _, t := range a {
if min > t { if min > t {
@ -44,7 +49,7 @@ func Min[T IntNumber | ~float64 | ~float32](a ...T) T {
return min return min
} }
func Max[T IntNumber | ~float64 | ~float32](a ...T) T { func Max[T Number](a ...T) T {
max := a[0] max := a[0]
for _, t := range a { for _, t := range a {
if max < t { if max < t {
@ -54,7 +59,7 @@ func Max[T IntNumber | ~float64 | ~float32](a ...T) T {
return max return max
} }
func Sum[T IntNumber | ~float64 | ~float32](a ...T) T { func Sum[T Number](a ...T) T {
s := T(0) s := T(0)
for _, t := range a { for _, t := range a {
s += t s += t
@ -62,6 +67,17 @@ func Sum[T IntNumber | ~float64 | ~float32](a ...T) T {
return s 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) return fmt.Sprintf("%v", n)
} }
func Abs[T Number](n T) T {
if n >= 0 {
return n
}
return -n
}

View File

@ -1,6 +1,9 @@
package slice 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 { func Map[T, R any](arr []T, fn func(T) R) []R {
r := make([]R, 0, len(arr)) 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 { func ToAnySlice[T any](a []T) []any {
return Map(a, helper.ToAny[T]) 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
}

View File

@ -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)
}
})
}
}

35
helper/slice/slices.go Normal file
View File

@ -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
}

View File

@ -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)
}