From 4e84bf21a07721361afd36789bda1dd6940514c3 Mon Sep 17 00:00:00 2001 From: xing Date: Fri, 27 Jan 2023 00:52:59 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helper/slice/slice.go | 26 ++++ helper/slice/slice_test.go | 124 ++++++++++++++++++ internal/actions/index.go | 3 +- internal/plugins/plugins.go | 2 + .../theme/twentyseventeen/twentyseventeen.go | 19 ++- 5 files changed, 169 insertions(+), 5 deletions(-) diff --git a/helper/slice/slice.go b/helper/slice/slice.go index d45b4ce..8c7caff 100644 --- a/helper/slice/slice.go +++ b/helper/slice/slice.go @@ -20,6 +20,32 @@ func FilterAndMap[N any, T any](arr []T, fn func(T) (N, bool)) (r []N) { return } +func Walk[T any](arr []T, fn func(*T)) { + for i := 0; i < len(arr); i++ { + fn(&arr[i]) + } +} + +func First[T any](arr []T, fn func(T) bool) (int, T) { + for i, t := range arr { + if fn(t) { + return i, t + } + } + var r T + return -1, r +} + +func Last[T any](arr []T, fn func(T) bool) (int, T) { + for i := len(arr) - 1; i > 0; i-- { + if fn(arr[i]) { + return i, arr[i] + } + } + var r T + return -1, r +} + func Filter[T any](arr []T, fn func(T) bool) []T { var r []T for _, t := range arr { diff --git a/helper/slice/slice_test.go b/helper/slice/slice_test.go index 126e0f4..9cc3a86 100644 --- a/helper/slice/slice_test.go +++ b/helper/slice/slice_test.go @@ -1,6 +1,7 @@ package slice import ( + "fmt" "github.com/fthvgb1/wp-go/helper/number" "reflect" "testing" @@ -527,3 +528,126 @@ func TestToAnySlice(t *testing.T) { }) } } + +func TestFirst(t *testing.T) { + type args[T int] struct { + arr []T + fn func(T) bool + } + type testCase[T int] struct { + name string + args args[T] + want int + want1 T + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + arr: number.Range(1, 10, 1), + fn: func(t int) bool { + return t == 5 + }, + }, + want: 4, + want1: 5, + }, { + name: "t2", + args: args[int]{ + arr: number.Range(1, 10, 1), + fn: func(t int) bool { + return t == 11 + }, + }, + want: -1, + want1: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := First(tt.args.arr, tt.args.fn) + if got != tt.want { + t.Errorf("First() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("First() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func TestLast(t *testing.T) { + type args[T int] struct { + arr []T + fn func(T) bool + } + type testCase[T int] struct { + name string + args args[T] + want int + want1 T + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + arr: []int{1, 55, 5, 5, 5, 5, 22}, + fn: func(t int) bool { + return t == 5 + }, + }, + want: 5, + want1: 5, + }, { + name: "t2", + args: args[int]{ + arr: number.Range(1, 10, 1), + fn: func(t int) bool { + return t == 11 + }, + }, + want: -1, + want1: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := Last(tt.args.arr, tt.args.fn) + if got != tt.want { + t.Errorf("Last() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("Last() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func TestWalk(t *testing.T) { + type args[T int] struct { + arr []T + fn func(*T) + } + type testCase[T int] struct { + name string + args args[T] + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{ + arr: number.Range(1, 10, 1), + fn: func(i *int) { + *i = *i * 2 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fmt.Println(tt.args.arr) + Walk(tt.args.arr, tt.args.fn) + fmt.Println(tt.args.arr) + }) + } +} diff --git a/internal/actions/index.go b/internal/actions/index.go index 87aa0b1..a05ea4d 100644 --- a/internal/actions/index.go +++ b/internal/actions/index.go @@ -140,6 +140,7 @@ func (h *indexHandle) parseParams() (err error) { if category == "" { category = h.c.Param("tag") if category != "" { + h.scene = plugins.Tag allNames := cache.AllTagsNames(h.c) if _, ok := allNames[category]; !ok { return errors.New(str.Join("not exists tag ", category)) @@ -148,6 +149,7 @@ func (h *indexHandle) parseParams() (err error) { h.header = fmt.Sprintf("标签: %s", category) } } else { + h.scene = plugins.Category allNames := cache.AllCategoryNames(h.c) if _, ok := allNames[category]; !ok { return errors.New(str.Join("not exists category ", category)) @@ -189,7 +191,6 @@ func (h *indexHandle) parseParams() (err error) { "left join", "wp_terms d", "c.term_id=d.term_id", }) h.setTitleLR(category, wpconfig.Options.Value("blogname")) - h.scene = plugins.Category } s := h.c.Query("s") if s != "" && strings.Replace(s, " ", "", -1) != "" { diff --git a/internal/plugins/plugins.go b/internal/plugins/plugins.go index 664533c..13568c7 100644 --- a/internal/plugins/plugins.go +++ b/internal/plugins/plugins.go @@ -8,6 +8,7 @@ const ( Home = iota + 1 Archive Category + Tag Search Detail @@ -21,6 +22,7 @@ var IndexSceneMap = map[int]struct{}{ Home: {}, Archive: {}, Category: {}, + Tag: {}, Search: {}, } diff --git a/internal/theme/twentyseventeen/twentyseventeen.go b/internal/theme/twentyseventeen/twentyseventeen.go index 44f3344..942c893 100644 --- a/internal/theme/twentyseventeen/twentyseventeen.go +++ b/internal/theme/twentyseventeen/twentyseventeen.go @@ -64,9 +64,19 @@ func Hook(status int, c *gin.Context, h gin.H, scene, stats int) { d = 0 } } else if scene == plugins.Category { - cate := slice.Filter(cache.Categories(c), func(my models.TermsMy) bool { - return my.Name == c.Param("category") - })[0] + cat := c.Param("category") + _, cate := slice.First(cache.Categories(c), func(my models.TermsMy) bool { + return my.Name == cat + }) + d = int(cate.Terms.TermId) + if cate.Slug[0] != '%' { + s = cate.Slug + } + } else if scene == plugins.Tag { + cat := c.Param("tag") + _, cate := slice.First(cache.Tags(c), func(my models.TermsMy) bool { + return my.Name == cat + }) d = int(cate.Terms.TermId) if cate.Slug[0] != '%' { s = cate.Slug @@ -175,7 +185,7 @@ func bodyClass(scene, d int, a ...any) string { } else { s = "search-no-results" } - } else if scene == plugins.Category { + } else if scene == plugins.Category || scene == plugins.Tag { s = fmt.Sprintf("category-%d %v", d, a[0]) } else if scene == plugins.Detail { s = fmt.Sprintf("postid-%d", d) @@ -184,6 +194,7 @@ func bodyClass(scene, d int, a ...any) string { plugins.Home: "home blog ", plugins.Archive: "archive date page-two-column", plugins.Category: str.Join("archive category page-two-column ", s), + plugins.Tag: str.Join("archive category page-two-column ", s), plugins.Search: str.Join("search ", s), plugins.Detail: str.Join("post-template-default single single-post single-format-standard ", s), }[scene] From 06e2f75000a7785f9fb527585a8a019523d8d7fe Mon Sep 17 00:00:00 2001 From: xing Date: Fri, 27 Jan 2023 01:03:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/theme/hook.go | 2 +- internal/theme/templateFuncs.go | 2 +- internal/theme/theme.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/theme/hook.go b/internal/theme/hook.go index 23ce9c8..3c7fa88 100644 --- a/internal/theme/hook.go +++ b/internal/theme/hook.go @@ -11,7 +11,7 @@ import ( var themeMap = map[string]func(int, *gin.Context, gin.H, int, int){} -func AddThemeHookFunc(name string, fn func(int, *gin.Context, gin.H, int, int)) { +func addThemeHookFunc(name string, fn func(int, *gin.Context, gin.H, int, int)) { if _, ok := themeMap[name]; ok { panic("exists same name theme") } diff --git a/internal/theme/templateFuncs.go b/internal/theme/templateFuncs.go index 2c7d0a6..b1f17c4 100644 --- a/internal/theme/templateFuncs.go +++ b/internal/theme/templateFuncs.go @@ -23,7 +23,7 @@ func FuncMap() template.FuncMap { return comFn } -func AddTemplateFunc(fnName string, fn any) { +func addTemplateFunc(fnName string, fn any) { if _, ok := comFn[fnName]; ok { panic("exists same name func") } diff --git a/internal/theme/theme.go b/internal/theme/theme.go index 67bcd78..bc0e23a 100644 --- a/internal/theme/theme.go +++ b/internal/theme/theme.go @@ -7,7 +7,7 @@ import ( ) func InitThemeAndTemplateFuncMap() { - AddThemeHookFunc(twentyseventeen.ThemeName, twentyseventeen.Hook) + addThemeHookFunc(twentyseventeen.ThemeName, twentyseventeen.Hook) } func GetTemplateName() string { From 0832d679a366989ddcabf383fa42d708d1502d0c Mon Sep 17 00:00:00 2001 From: xing Date: Fri, 27 Jan 2023 23:48:48 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=87=A0=E4=B8=AAphp?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E7=BB=84=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helper/maps/map.go | 12 +++ helper/number/number.go | 24 ++++- helper/slice/slice.go | 65 ++++++++++++- helper/slice/slice_test.go | 189 ++++++++++++++++++++++++++++++++++++ helper/slice/slices.go | 35 +++++++ helper/slice/slices_test.go | 79 +++++++++++++++ 6 files changed, 399 insertions(+), 5 deletions(-) create mode 100644 helper/slice/slices.go create mode 100644 helper/slice/slices_test.go 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) +} From e94165f63cf0168de36a97aee441620601521e18 Mon Sep 17 00:00:00 2001 From: xing Date: Sat, 28 Jan 2023 21:38:34 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=20=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helper/number/number.go | 17 ++++++ helper/number/number_test.go | 27 +++++++++ helper/slice/slice.go | 11 +++- helper/slice/slice_test.go | 16 +++--- helper/slice/slices.go | 24 ++++++++ helper/slice/slices_test.go | 57 +++++++++++++++++++ .../theme/twentyseventeen/twentyseventeen.go | 4 +- 7 files changed, 143 insertions(+), 13 deletions(-) diff --git a/helper/number/number.go b/helper/number/number.go index fc4fa0c..7198d30 100644 --- a/helper/number/number.go +++ b/helper/number/number.go @@ -3,8 +3,14 @@ package number import ( "fmt" "math/rand" + "time" ) +var _ = func() any { + rand.Seed(time.Now().UnixNano()) + return nil +}() + type IntNumber interface { ~int | ~int64 | ~int32 | ~int8 | ~int16 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 @@ -70,6 +76,9 @@ func Sum[T Number](a ...T) T { func Add[T Number](i, j T) T { return i + j } +func Sub[T Number](i, j T) T { + return i - j +} func ToString[T Number](n T) string { return fmt.Sprintf("%v", n) @@ -81,3 +90,11 @@ func Abs[T Number](n T) T { } return -n } + +func Mul[T Number](i, j T) T { + return i * j +} + +func Divide[T Number](i, j T) T { + return i / j +} diff --git a/helper/number/number_test.go b/helper/number/number_test.go index 5c44cda..5cc7a94 100644 --- a/helper/number/number_test.go +++ b/helper/number/number_test.go @@ -1,6 +1,7 @@ package number import ( + "fmt" "reflect" "testing" ) @@ -187,6 +188,32 @@ func TestRand(t *testing.T) { if got > tt.args.end || got < tt.args.start { t.Errorf("RandNum() = %v, range error", got) } + fmt.Println(got) + } + }) + } +} + +func TestAbs(t *testing.T) { + type args[T Number] struct { + n T + } + type testCase[T Number] struct { + name string + args args[T] + want T + } + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{-1}, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Abs(tt.args.n); got != tt.want { + t.Errorf("Abs() = %v, want %v", got, tt.want) } }) } diff --git a/helper/slice/slice.go b/helper/slice/slice.go index 4c5c2ca..0cb7366 100644 --- a/helper/slice/slice.go +++ b/helper/slice/slice.go @@ -29,7 +29,7 @@ func Walk[T any](arr []T, fn func(*T)) { } } -func First[T any](arr []T, fn func(T) bool) (int, T) { +func SearchFirst[T any](arr []T, fn func(T) bool) (int, T) { for i, t := range arr { if fn(t) { return i, t @@ -39,7 +39,7 @@ func First[T any](arr []T, fn func(T) bool) (int, T) { return -1, r } -func Last[T any](arr []T, fn func(T) bool) (int, T) { +func SearchLast[T any](arr []T, fn func(T) bool) (int, T) { for i := len(arr) - 1; i > 0; i-- { if fn(arr[i]) { return i, arr[i] @@ -194,6 +194,7 @@ func ToAnySlice[T any](a []T) []any { return Map(a, helper.ToAny[T]) } +// Fill 用指定值填充一个切片 func Fill[T any](start, len int, v T) []T { r := make([]T, start+len) for i := 0; i < len; i++ { @@ -202,7 +203,7 @@ func Fill[T any](start, len int, v T) []T { 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. +// 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 { @@ -213,6 +214,7 @@ func Pad[T any](a []T, length int, v T) []T { return a } +// Pop 弹出最后一个元素 func Pop[T any](a *[]T) T { arr := *a v := arr[len(arr)-1] @@ -221,11 +223,13 @@ func Pop[T any](a *[]T) T { return v } +// Rand 随机取一个元素 func Rand[T any](a []T) (int, T) { i := number.Rand(0, len(a)-1) return i, a[i] } +// RandPop 随机弹出一个元素并返回那个剩余长度 func RandPop[T any](a *[]T) (T, int) { arr := *a if len(arr) == 0 { @@ -242,6 +246,7 @@ func RandPop[T any](a *[]T) (T, int) { return v, len(arr) - 1 } +// Shift 将切片的第一个单元移出并作为结果返回 func Shift[T any](a *[]T) (T, int) { arr := *a l := len(arr) diff --git a/helper/slice/slice_test.go b/helper/slice/slice_test.go index 71dd85b..e4b9968 100644 --- a/helper/slice/slice_test.go +++ b/helper/slice/slice_test.go @@ -529,7 +529,7 @@ func TestToAnySlice(t *testing.T) { } } -func TestFirst(t *testing.T) { +func TestSearchFirst(t *testing.T) { type args[T int] struct { arr []T fn func(T) bool @@ -565,18 +565,18 @@ func TestFirst(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, got1 := First(tt.args.arr, tt.args.fn) + got, got1 := SearchFirst(tt.args.arr, tt.args.fn) if got != tt.want { - t.Errorf("First() got = %v, want %v", got, tt.want) + t.Errorf("SearchFirst() got = %v, want %v", got, tt.want) } if !reflect.DeepEqual(got1, tt.want1) { - t.Errorf("First() got1 = %v, want %v", got1, tt.want1) + t.Errorf("SearchFirst() got1 = %v, want %v", got1, tt.want1) } }) } } -func TestLast(t *testing.T) { +func TestSearchLast(t *testing.T) { type args[T int] struct { arr []T fn func(T) bool @@ -612,12 +612,12 @@ func TestLast(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, got1 := Last(tt.args.arr, tt.args.fn) + got, got1 := SearchLast(tt.args.arr, tt.args.fn) if got != tt.want { - t.Errorf("Last() got = %v, want %v", got, tt.want) + t.Errorf("SearchLast() got = %v, want %v", got, tt.want) } if !reflect.DeepEqual(got1, tt.want1) { - t.Errorf("Last() got1 = %v, want %v", got1, tt.want1) + t.Errorf("SearchLast() got1 = %v, want %v", got1, tt.want1) } }) } diff --git a/helper/slice/slices.go b/helper/slice/slices.go index 5c95c9d..8fb1af0 100644 --- a/helper/slice/slices.go +++ b/helper/slice/slices.go @@ -33,3 +33,27 @@ func Splice[T any](a *[]T, offset, length int, replacement []T) []T { } return nil } + +func Shuffle[T any](a *[]T) { + if len(*a) < 1 { + return + } + b := make([]T, 0, len(*a)) + for { + v, l := RandPop(a) + b = append(b, v) + if l < 1 { + break + } + + } + *a = b +} + +func Delete[T any](a *[]T, index int) { + if index >= len(*a) || index < 0 { + return + } + arr := *a + *a = append(arr[:index], arr[index+1:]...) +} diff --git a/helper/slice/slices_test.go b/helper/slice/slices_test.go index e7f19bd..cdc150a 100644 --- a/helper/slice/slices_test.go +++ b/helper/slice/slices_test.go @@ -77,3 +77,60 @@ func TestSplice(t *testing.T) { fmt.Println(c) fmt.Println(d) } + +func TestShuffle(t *testing.T) { + type args[T int] struct { + a *[]T + } + type testCase[T int] struct { + name string + args args[T] + } + 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 < 20; i++ { + Shuffle(tt.args.a) + fmt.Println(a) + } + }) + } +} + +func TestDelete(t *testing.T) { + type args[T int] struct { + a *[]T + index int + } + type testCase[T int] struct { + name string + args args[T] + } + a := number.Range(1, 5, 1) + b := number.Range(1, 5, 1) + fmt.Println(a) + fmt.Println(b) + tests := []testCase[int]{ + { + name: "t1", + args: args[int]{&a, 0}, + }, + { + name: "t2", + args: args[int]{&b, 2}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + Delete(tt.args.a, tt.args.index) + }) + } + fmt.Println(a) + fmt.Println(b) +} diff --git a/internal/theme/twentyseventeen/twentyseventeen.go b/internal/theme/twentyseventeen/twentyseventeen.go index 942c893..728d44a 100644 --- a/internal/theme/twentyseventeen/twentyseventeen.go +++ b/internal/theme/twentyseventeen/twentyseventeen.go @@ -65,7 +65,7 @@ func Hook(status int, c *gin.Context, h gin.H, scene, stats int) { } } else if scene == plugins.Category { cat := c.Param("category") - _, cate := slice.First(cache.Categories(c), func(my models.TermsMy) bool { + _, cate := slice.SearchFirst(cache.Categories(c), func(my models.TermsMy) bool { return my.Name == cat }) d = int(cate.Terms.TermId) @@ -74,7 +74,7 @@ func Hook(status int, c *gin.Context, h gin.H, scene, stats int) { } } else if scene == plugins.Tag { cat := c.Param("tag") - _, cate := slice.First(cache.Tags(c), func(my models.TermsMy) bool { + _, cate := slice.SearchFirst(cache.Tags(c), func(my models.TermsMy) bool { return my.Name == cat }) d = int(cate.Terms.TermId) From a983f9088186bfac2f69e755d961443bd88b100b Mon Sep 17 00:00:00 2001 From: xing Date: Sat, 28 Jan 2023 22:36:15 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stream/simpleMapStream.go | 26 +-- stream/simpleMapStream_test.go | 26 +-- stream/simpleStream.go | 149 ------------------ stream/stream.go | 149 ++++++++++++++++++ .../{simpleStream_test.go => stream_test.go} | 132 ++++++++-------- 5 files changed, 241 insertions(+), 241 deletions(-) delete mode 100644 stream/simpleStream.go create mode 100644 stream/stream.go rename stream/{simpleStream_test.go => stream_test.go} (76%) diff --git a/stream/simpleMapStream.go b/stream/simpleMapStream.go index b3a352c..5c4e379 100644 --- a/stream/simpleMapStream.go +++ b/stream/simpleMapStream.go @@ -24,11 +24,11 @@ func newMapX[K comparable, V any]() mapX[K, V] { } } -func SimpleMapFilterAndMapToSlice[R any, K comparable, V any](mm SimpleMapStream[K, V], fn func(K, V) (R, bool)) SimpleSliceStream[R] { - return NewSimpleSliceStream(maps.FilterToSlice(mm.m, fn)) +func SimpleMapFilterAndMapToSlice[R any, K comparable, V any](mm MapStream[K, V], fn func(K, V) (R, bool)) Stream[R] { + return NewStream(maps.FilterToSlice(mm.m, fn)) } -func SimpleMapParallelFilterAndMapToMap[K comparable, V any, KK comparable, VV any](mm SimpleMapStream[KK, VV], fn func(KK, VV) (K, V, bool), c int) SimpleMapStream[K, V] { +func SimpleMapParallelFilterAndMapToMap[K comparable, V any, KK comparable, VV any](mm MapStream[KK, VV], fn func(KK, VV) (K, V, bool), c int) MapStream[K, V] { m := newMapX[K, V]() mm.ParallelForEach(func(kk KK, vv VV) { k, v, ok := fn(kk, vv) @@ -36,11 +36,11 @@ func SimpleMapParallelFilterAndMapToMap[K comparable, V any, KK comparable, VV a m.set(k, v) } }, c) - return SimpleMapStream[K, V]{m.m} + return MapStream[K, V]{m.m} } -func SimpleMapStreamFilterAndMapToMap[K comparable, V any, KK comparable, VV comparable](a SimpleMapStream[KK, VV], fn func(KK, VV) (K, V, bool)) (r SimpleMapStream[K, V]) { - r = SimpleMapStream[K, V]{make(map[K]V)} +func SimpleMapStreamFilterAndMapToMap[K comparable, V any, KK comparable, VV comparable](a MapStream[KK, VV], fn func(KK, VV) (K, V, bool)) (r MapStream[K, V]) { + r = MapStream[K, V]{make(map[K]V)} for k, v := range a.m { kk, vv, ok := fn(k, v) if ok { @@ -50,21 +50,21 @@ func SimpleMapStreamFilterAndMapToMap[K comparable, V any, KK comparable, VV com return } -func NewSimpleMapStream[K comparable, V any](m map[K]V) SimpleMapStream[K, V] { - return SimpleMapStream[K, V]{m} +func NewSimpleMapStream[K comparable, V any](m map[K]V) MapStream[K, V] { + return MapStream[K, V]{m} } -type SimpleMapStream[K comparable, V any] struct { +type MapStream[K comparable, V any] struct { m map[K]V } -func (r SimpleMapStream[K, V]) ForEach(fn func(K, V)) { +func (r MapStream[K, V]) ForEach(fn func(K, V)) { for k, v := range r.m { fn(k, v) } } -func (r SimpleMapStream[K, V]) ParallelForEach(fn func(K, V), c int) { +func (r MapStream[K, V]) ParallelForEach(fn func(K, V), c int) { p := taskPools.NewPools(c) for k, v := range r.m { k := k @@ -76,10 +76,10 @@ func (r SimpleMapStream[K, V]) ParallelForEach(fn func(K, V), c int) { p.Wait() } -func (r SimpleMapStream[K, V]) Len() int { +func (r MapStream[K, V]) Len() int { return len(r.m) } -func (r SimpleMapStream[K, V]) Result() map[K]V { +func (r MapStream[K, V]) Result() map[K]V { return r.m } diff --git a/stream/simpleMapStream_test.go b/stream/simpleMapStream_test.go index 0c064e1..efaf9c8 100644 --- a/stream/simpleMapStream_test.go +++ b/stream/simpleMapStream_test.go @@ -16,13 +16,13 @@ func TestNewSimpleMapStream(t *testing.T) { type testCase[K int, V int] struct { name string args args[K, V] - want SimpleMapStream[K, V] + want MapStream[K, V] } tests := []testCase[int, int]{ { name: "t1", args: args[int, int]{make(map[int]int)}, - want: SimpleMapStream[int, int]{make(map[int]int)}, + want: MapStream[int, int]{make(map[int]int)}, }, } for _, tt := range tests { @@ -41,14 +41,14 @@ var w = slice.ToMap(y, func(v int) (int, int) { func TestSimpleMapFilterAndMapToSlice(t *testing.T) { type args[K int, V int, R int] struct { - mm SimpleMapStream[K, V] + mm MapStream[K, V] fn func(K, V) (R, bool) c int } type testCase[K int, V int, R int] struct { name string args args[K, V, R] - want SimpleSliceStream[R] + want Stream[R] } tests := []testCase[int, int, int]{ { @@ -63,7 +63,7 @@ func TestSimpleMapFilterAndMapToSlice(t *testing.T) { }, c: 6, }, - want: NewSimpleSliceStream(y[500:]), + want: NewStream(y[500:]), }, } for _, tt := range tests { @@ -79,14 +79,14 @@ func TestSimpleMapFilterAndMapToSlice(t *testing.T) { func TestSimpleMapParallelFilterAndMapToMap(t *testing.T) { type args[KK string, VV string, K int, V int] struct { - mm SimpleMapStream[K, V] + mm MapStream[K, V] fn func(K, V) (KK, VV, bool) c int } type testCase[KK string, VV string, K int, V int] struct { name string args args[KK, VV, K, V] - want SimpleMapStream[KK, VV] + want MapStream[KK, VV] } tests := []testCase[string, string, int, int]{ { @@ -119,13 +119,13 @@ func TestSimpleMapParallelFilterAndMapToMap(t *testing.T) { func TestSimpleMapStreamFilterAndMapToMap(t *testing.T) { type args[KK string, VV string, K int, V int] struct { - a SimpleMapStream[K, V] + a MapStream[K, V] fn func(K, V) (KK, VV, bool) } type testCase[KK string, VV string, K int, V int] struct { name string args args[KK, VV, K, V] - wantR SimpleMapStream[KK, VV] + wantR MapStream[KK, VV] } tests := []testCase[string, string, int, int]{ { @@ -161,7 +161,7 @@ func TestSimpleMapStream_ForEach(t *testing.T) { } type testCase[K int, V int] struct { name string - r SimpleMapStream[K, V] + r MapStream[K, V] args args[K, V] } tests := []testCase[int, int]{ @@ -187,7 +187,7 @@ func TestSimpleMapStream_ForEach(t *testing.T) { func TestSimpleMapStream_Len(t *testing.T) { type testCase[K int, V int] struct { name string - r SimpleMapStream[K, V] + r MapStream[K, V] want int } tests := []testCase[int, int]{ @@ -213,7 +213,7 @@ func TestSimpleMapStream_ParallelForEach(t *testing.T) { } type testCase[K int, V int] struct { name string - r SimpleMapStream[K, V] + r MapStream[K, V] args args[K, V] } tests := []testCase[int, int]{ @@ -238,7 +238,7 @@ func TestSimpleMapStream_ParallelForEach(t *testing.T) { func TestSimpleMapStream_Result(t *testing.T) { type testCase[K int, V int] struct { name string - r SimpleMapStream[K, V] + r MapStream[K, V] want map[K]V } tests := []testCase[int, int]{ diff --git a/stream/simpleStream.go b/stream/simpleStream.go deleted file mode 100644 index 6592db9..0000000 --- a/stream/simpleStream.go +++ /dev/null @@ -1,149 +0,0 @@ -package stream - -import ( - "github.com/fthvgb1/wp-go/helper/slice" - "github.com/fthvgb1/wp-go/safety" - "github.com/fthvgb1/wp-go/taskPools" -) - -func SimpleParallelFilterAndMap[R, T any](a SimpleSliceStream[T], fn func(T) (R, bool), c int) SimpleSliceStream[R] { - var x []R - rr := safety.NewSlice(x) - a.ParallelForEach(func(t T) { - y, ok := fn(t) - if ok { - rr.Append(y) - } - }, c) - return SimpleSliceStream[R]{rr.Load()} -} - -func SimpleParallelFilterAndMapToMap[K comparable, V any, T any](a SimpleSliceStream[T], fn func(t T) (K, V, bool), c int) (r SimpleMapStream[K, V]) { - m := newMapX[K, V]() - a.ParallelForEach(func(t T) { - k, v, ok := fn(t) - if ok { - m.set(k, v) - } - }, c) - var mm = map[K]V{} - r = NewSimpleMapStream(mm) - return -} - -func SimpleSliceFilterAndMapToMap[K comparable, V any, T any](a SimpleSliceStream[T], fn func(t T) (K, V, bool), isCoverPrev bool) (r SimpleMapStream[K, V]) { - m := make(map[K]V) - a.ForEach(func(t T) { - k, v, ok := fn(t) - if ok { - _, ok = m[k] - if isCoverPrev || !ok { - m[k] = v - } - } - }) - r.m = m - return -} - -func SimpleStreamFilterAndMap[R, T any](a SimpleSliceStream[T], fn func(T) (R, bool)) SimpleSliceStream[R] { - return NewSimpleSliceStream(slice.FilterAndMap(a.arr, fn)) -} - -func SimpleParallelMap[R, T any](a SimpleSliceStream[T], fn func(T) R, c int) SimpleSliceStream[R] { - var x []R - rr := safety.NewSlice(x) - a.ParallelForEach(func(t T) { - rr.Append(fn(t)) - }, c) - return SimpleSliceStream[R]{rr.Load()} -} -func SimpleStreamMap[R, T any](a SimpleSliceStream[T], fn func(T) R) SimpleSliceStream[R] { - return NewSimpleSliceStream(slice.Map(a.arr, fn)) -} - -func Reduce[T any, S any](s SimpleSliceStream[S], fn func(S, T) T, init T) (r T) { - return slice.Reduce(s.arr, fn, init) -} - -func NewSimpleSliceStream[T any](arr []T) SimpleSliceStream[T] { - return SimpleSliceStream[T]{arr: arr} -} - -type SimpleSliceStream[T any] struct { - arr []T -} - -func (r SimpleSliceStream[T]) ForEach(fn func(T)) { - for _, t := range r.arr { - fn(t) - } -} - -func (r SimpleSliceStream[T]) ParallelForEach(fn func(T), c int) { - p := taskPools.NewPools(c) - for _, t := range r.arr { - t := t - p.Execute(func() { - fn(t) - }) - } - p.Wait() -} - -func (r SimpleSliceStream[T]) ParallelFilter(fn func(T) bool, c int) SimpleSliceStream[T] { - rr := safety.NewSlice([]T{}) - r.ParallelForEach(func(t T) { - if fn(t) { - rr.Append(t) - } - }, c) - return SimpleSliceStream[T]{rr.Load()} -} -func (r SimpleSliceStream[T]) Filter(fn func(T) bool) SimpleSliceStream[T] { - r.arr = slice.Filter(r.arr, fn) - return r -} - -func (r SimpleSliceStream[T]) ParallelMap(fn func(T) T, c int) SimpleSliceStream[T] { - rr := safety.NewSlice([]T{}) - r.ParallelForEach(func(t T) { - rr.Append(fn(t)) - }, c) - return SimpleSliceStream[T]{rr.Load()} -} - -func (r SimpleSliceStream[T]) Map(fn func(T) T) SimpleSliceStream[T] { - r.arr = slice.Map(r.arr, fn) - return r -} - -func (r SimpleSliceStream[T]) Sort(fn func(i, j T) bool) SimpleSliceStream[T] { - slice.SortSelf(r.arr, fn) - return r -} - -func (r SimpleSliceStream[T]) Len() int { - return len(r.arr) -} - -func (r SimpleSliceStream[T]) Limit(limit, offset int) SimpleSliceStream[T] { - l := len(r.arr) - if offset >= l { - return SimpleSliceStream[T]{} - } - ll := offset + limit - if ll > l { - ll = l - } - return SimpleSliceStream[T]{r.arr[offset:ll]} -} - -func (r SimpleSliceStream[T]) Reverse() SimpleSliceStream[T] { - slice.ReverseSelf(r.arr) - return r -} - -func (r SimpleSliceStream[T]) Result() []T { - return r.arr -} diff --git a/stream/stream.go b/stream/stream.go new file mode 100644 index 0000000..24ef73f --- /dev/null +++ b/stream/stream.go @@ -0,0 +1,149 @@ +package stream + +import ( + "github.com/fthvgb1/wp-go/helper/slice" + "github.com/fthvgb1/wp-go/safety" + "github.com/fthvgb1/wp-go/taskPools" +) + +func ParallelFilterAndMap[R, T any](a Stream[T], fn func(T) (R, bool), c int) Stream[R] { + var x []R + rr := safety.NewSlice(x) + a.ParallelForEach(func(t T) { + y, ok := fn(t) + if ok { + rr.Append(y) + } + }, c) + return Stream[R]{rr.Load()} +} + +func ParallelFilterAndMapToMapStream[K comparable, V any, T any](a Stream[T], fn func(t T) (K, V, bool), c int) (r MapStream[K, V]) { + m := newMapX[K, V]() + a.ParallelForEach(func(t T) { + k, v, ok := fn(t) + if ok { + m.set(k, v) + } + }, c) + var mm = map[K]V{} + r = NewSimpleMapStream(mm) + return +} + +func SliceFilterAndMapToMapStream[K comparable, V any, T any](a Stream[T], fn func(t T) (K, V, bool), isCoverPrev bool) (r MapStream[K, V]) { + m := make(map[K]V) + a.ForEach(func(t T) { + k, v, ok := fn(t) + if ok { + _, ok = m[k] + if isCoverPrev || !ok { + m[k] = v + } + } + }) + r.m = m + return +} + +func FilterAndMapNewStream[R, T any](a Stream[T], fn func(T) (R, bool)) Stream[R] { + return NewStream(slice.FilterAndMap(a.arr, fn)) +} + +func ParallelMap[R, T any](a Stream[T], fn func(T) R, c int) Stream[R] { + var x []R + rr := safety.NewSlice(x) + a.ParallelForEach(func(t T) { + rr.Append(fn(t)) + }, c) + return Stream[R]{rr.Load()} +} +func MapNewStream[R, T any](a Stream[T], fn func(T) R) Stream[R] { + return NewStream(slice.Map(a.arr, fn)) +} + +func Reduce[T any, S any](s Stream[S], fn func(S, T) T, init T) (r T) { + return slice.Reduce(s.arr, fn, init) +} + +func NewStream[T any](arr []T) Stream[T] { + return Stream[T]{arr: arr} +} + +type Stream[T any] struct { + arr []T +} + +func (r Stream[T]) ForEach(fn func(T)) { + for _, t := range r.arr { + fn(t) + } +} + +func (r Stream[T]) ParallelForEach(fn func(T), c int) { + p := taskPools.NewPools(c) + for _, t := range r.arr { + t := t + p.Execute(func() { + fn(t) + }) + } + p.Wait() +} + +func (r Stream[T]) ParallelFilter(fn func(T) bool, c int) Stream[T] { + rr := safety.NewSlice([]T{}) + r.ParallelForEach(func(t T) { + if fn(t) { + rr.Append(t) + } + }, c) + return Stream[T]{rr.Load()} +} +func (r Stream[T]) Filter(fn func(T) bool) Stream[T] { + r.arr = slice.Filter(r.arr, fn) + return r +} + +func (r Stream[T]) ParallelMap(fn func(T) T, c int) Stream[T] { + rr := safety.NewSlice([]T{}) + r.ParallelForEach(func(t T) { + rr.Append(fn(t)) + }, c) + return Stream[T]{rr.Load()} +} + +func (r Stream[T]) Map(fn func(T) T) Stream[T] { + r.arr = slice.Map(r.arr, fn) + return r +} + +func (r Stream[T]) Sort(fn func(i, j T) bool) Stream[T] { + slice.SortSelf(r.arr, fn) + return r +} + +func (r Stream[T]) Len() int { + return len(r.arr) +} + +func (r Stream[T]) Limit(limit, offset int) Stream[T] { + l := len(r.arr) + if offset >= l { + return Stream[T]{} + } + ll := offset + limit + if ll > l { + ll = l + } + return Stream[T]{r.arr[offset:ll]} +} + +func (r Stream[T]) Reverse() Stream[T] { + slice.ReverseSelf(r.arr) + return r +} + +func (r Stream[T]) Result() []T { + return r.arr +} diff --git a/stream/simpleStream_test.go b/stream/stream_test.go similarity index 76% rename from stream/simpleStream_test.go rename to stream/stream_test.go index ba0ffa6..954d7a6 100644 --- a/stream/simpleStream_test.go +++ b/stream/stream_test.go @@ -9,7 +9,7 @@ import ( "testing" ) -var s = NewSimpleSliceStream(number.Range(1, 10, 1)) +var s = NewStream(number.Range(1, 10, 1)) func TestSimpleSliceStream_Filter(t *testing.T) { type args[T int] struct { @@ -17,9 +17,9 @@ func TestSimpleSliceStream_Filter(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -33,7 +33,7 @@ func TestSimpleSliceStream_Filter(t *testing.T) { return }, }, - want: SimpleSliceStream[int]{number.Range(6, 10, 1)}, + want: Stream[int]{number.Range(6, 10, 1)}, }, } for _, tt := range tests { @@ -51,7 +51,7 @@ func TestSimpleSliceStream_ForEach(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] } tests := []testCase[int]{ @@ -79,9 +79,9 @@ func TestSimpleSliceStream_Limit(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -91,7 +91,7 @@ func TestSimpleSliceStream_Limit(t *testing.T) { limit: 3, offset: 5, }, - want: SimpleSliceStream[int]{number.Range(6, 8, 1)}, + want: Stream[int]{number.Range(6, 8, 1)}, }, { name: "t2", @@ -100,7 +100,7 @@ func TestSimpleSliceStream_Limit(t *testing.T) { limit: 3, offset: 9, }, - want: SimpleSliceStream[int]{number.Range(10, 10, 1)}, + want: Stream[int]{number.Range(10, 10, 1)}, }, { name: "t3", @@ -109,7 +109,7 @@ func TestSimpleSliceStream_Limit(t *testing.T) { limit: 3, offset: 11, }, - want: SimpleSliceStream[int]{}, + want: Stream[int]{}, }, } for _, tt := range tests { @@ -127,9 +127,9 @@ func TestSimpleSliceStream_Map(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -140,13 +140,13 @@ func TestSimpleSliceStream_Map(t *testing.T) { return t * 2 }, }, - want: SimpleSliceStream[int]{number.Range(2, 20, 2)}, + want: Stream[int]{number.Range(2, 20, 2)}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.r.Map(tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Map() = %v, want %v", got, tt.want) + t.Errorf("MapNewStream() = %v, want %v", got, tt.want) } }) } @@ -155,7 +155,7 @@ func TestSimpleSliceStream_Map(t *testing.T) { func TestSimpleSliceStream_Result(t *testing.T) { type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] want []T } tests := []testCase[int]{ @@ -180,9 +180,9 @@ func TestSimpleSliceStream_Sort(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -193,7 +193,7 @@ func TestSimpleSliceStream_Sort(t *testing.T) { return i > j }, }, - want: SimpleSliceStream[int]{number.Range(10, 1, -1)}, + want: Stream[int]{number.Range(10, 1, -1)}, }, } for _, tt := range tests { @@ -212,7 +212,7 @@ func TestSimpleSliceStream_parallelForEach(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] } tests := []testCase[int]{ @@ -241,9 +241,9 @@ func TestSimpleSliceStream_ParallelFilter(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -255,7 +255,7 @@ func TestSimpleSliceStream_ParallelFilter(t *testing.T) { }, c: 6, }, - want: SimpleSliceStream[int]{number.Range(4, 10, 1)}, + want: Stream[int]{number.Range(4, 10, 1)}, }, } for _, tt := range tests { @@ -276,9 +276,9 @@ func TestSimpleSliceStream_ParallelMap(t *testing.T) { } type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] args args[T] - want SimpleSliceStream[T] + want Stream[T] } tests := []testCase[int]{ { @@ -290,7 +290,7 @@ func TestSimpleSliceStream_ParallelMap(t *testing.T) { }, c: 6, }, - want: SimpleSliceStream[int]{number.Range(2, 20, 2)}, + want: Stream[int]{number.Range(2, 20, 2)}, }, } for _, tt := range tests { @@ -298,7 +298,7 @@ func TestSimpleSliceStream_ParallelMap(t *testing.T) { if got := tt.r.ParallelMap(tt.args.fn, tt.args.c).Sort(func(i, j int) bool { return i < j }); !reflect.DeepEqual(got, tt.want) { - t.Errorf("SimpleParallelMap() = %v, want %v", got, tt.want) + t.Errorf("ParallelMap() = %v, want %v", got, tt.want) } }) } @@ -306,7 +306,7 @@ func TestSimpleSliceStream_ParallelMap(t *testing.T) { func TestReduce(t *testing.T) { type args[S, T int] struct { - s SimpleSliceStream[S] + s Stream[S] fn func(S, T) T init T } @@ -339,14 +339,14 @@ func TestReduce(t *testing.T) { func TestSimpleSliceStream_Reverse(t *testing.T) { type testCase[T int] struct { name string - r SimpleSliceStream[T] - want SimpleSliceStream[T] + r Stream[T] + want Stream[T] } tests := []testCase[int]{ { name: "t1", - r: NewSimpleSliceStream(number.Range(1, 10, 1)), - want: SimpleSliceStream[int]{number.Range(10, 1, -1)}, + r: NewStream(number.Range(1, 10, 1)), + want: Stream[int]{number.Range(10, 1, -1)}, }, } for _, tt := range tests { @@ -362,30 +362,30 @@ var x = number.Range(1, 100000, 1) func TestSimpleStreamMap(t *testing.T) { type args[T int, R string] struct { - a SimpleSliceStream[T] + a Stream[T] fn func(T) R } type testCase[T int, R string] struct { name string args args[T, R] - want SimpleSliceStream[R] + want Stream[R] } tests := []testCase[int, string]{ { name: "t1", args: args[int, string]{ - a: NewSimpleSliceStream(x), + a: NewStream(x), fn: strconv.Itoa, }, - want: SimpleSliceStream[string]{ + want: Stream[string]{ slice.Map(x, strconv.Itoa), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := SimpleStreamMap(tt.args.a, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("SimpleStreamMap() = %v, want %v", got, tt.want) + if got := MapNewStream(tt.args.a, tt.args.fn); !reflect.DeepEqual(got, tt.want) { + t.Errorf("MapNewStream() = %v, want %v", got, tt.want) } }) } @@ -393,36 +393,36 @@ func TestSimpleStreamMap(t *testing.T) { func TestSimpleParallelMap(t *testing.T) { type args[T string, R int] struct { - a SimpleSliceStream[string] + a Stream[string] fn func(T) R c int } type testCase[T string, R int] struct { name string args args[T, R] - want SimpleSliceStream[R] + want Stream[R] } tests := []testCase[string, int]{ { name: "t1", args: args[string, int]{ - a: NewSimpleSliceStream(slice.Map(x, strconv.Itoa)), + a: NewStream(slice.Map(x, strconv.Itoa)), fn: func(s string) int { i, _ := strconv.Atoi(s) return i }, c: 6, }, - want: NewSimpleSliceStream(x), + want: NewStream(x), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := SimpleParallelMap(tt.args.a, tt.args.fn, tt.args.c).Sort(func(i, j int) bool { + if got := ParallelMap(tt.args.a, tt.args.fn, tt.args.c).Sort(func(i, j int) bool { return i < j }); !reflect.DeepEqual(got, tt.want) { - t.Errorf("SimpleParallelMap() = %v, want %v", got, tt.want) + t.Errorf("ParallelMap() = %v, want %v", got, tt.want) } }) } @@ -430,20 +430,20 @@ func TestSimpleParallelMap(t *testing.T) { func TestSimpleParallelFilterAndMap(t *testing.T) { type args[T string, R int] struct { - a SimpleSliceStream[string] + a Stream[string] fn func(T) (R, bool) c int } type testCase[T string, R int] struct { name string args args[T, R] - want SimpleSliceStream[R] + want Stream[R] } tests := []testCase[string, int]{ { name: "t1", args: args[string, int]{ - a: NewSimpleSliceStream(slice.Map(x, strconv.Itoa)), + a: NewStream(slice.Map(x, strconv.Itoa)), fn: func(s string) (int, bool) { i, _ := strconv.Atoi(s) if i > 50000 { @@ -453,15 +453,15 @@ func TestSimpleParallelFilterAndMap(t *testing.T) { }, c: 6, }, - want: NewSimpleSliceStream(x[50000:]), + want: NewStream(x[50000:]), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := SimpleParallelFilterAndMap(tt.args.a, tt.args.fn, tt.args.c).Sort(func(i, j int) bool { + if got := ParallelFilterAndMap(tt.args.a, tt.args.fn, tt.args.c).Sort(func(i, j int) bool { return i < j }); !reflect.DeepEqual(got, tt.want) { - t.Errorf("SimpleParallelFilterAndMap() = %v, want %v", got, tt.want) + t.Errorf("ParallelFilterAndMap() = %v, want %v", got, tt.want) } }) } @@ -469,19 +469,19 @@ func TestSimpleParallelFilterAndMap(t *testing.T) { func TestSimpleStreamFilterAndMap(t *testing.T) { type args[T string, R int] struct { - a SimpleSliceStream[T] + a Stream[T] fn func(T) (R, bool) } type testCase[T any, R any] struct { name string args args[string, int] - want SimpleSliceStream[R] + want Stream[R] } tests := []testCase[string, int]{ { name: "t1", args: args[string, int]{ - a: NewSimpleSliceStream(slice.Map(x, strconv.Itoa)), + a: NewStream(slice.Map(x, strconv.Itoa)), fn: func(s string) (int, bool) { i, _ := strconv.Atoi(s) if i > 50000 { @@ -490,13 +490,13 @@ func TestSimpleStreamFilterAndMap(t *testing.T) { return 0, false }, }, - want: NewSimpleSliceStream(x[50000:]), + want: NewStream(x[50000:]), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := SimpleStreamFilterAndMap(tt.args.a, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("SimpleStreamFilterAndMap() = %v, want %v", got, tt.want) + if got := FilterAndMapNewStream(tt.args.a, tt.args.fn); !reflect.DeepEqual(got, tt.want) { + t.Errorf("FilterAndMapNewStream() = %v, want %v", got, tt.want) } }) } @@ -505,7 +505,7 @@ func TestSimpleStreamFilterAndMap(t *testing.T) { func TestSimpleSliceStream_Len(t *testing.T) { type testCase[T int] struct { name string - r SimpleSliceStream[T] + r Stream[T] want int } tests := []testCase[int]{ @@ -526,20 +526,20 @@ func TestSimpleSliceStream_Len(t *testing.T) { func TestSimpleParallelFilterAndMapToMap(t *testing.T) { type args[T int, K int, V int] struct { - a SimpleSliceStream[V] + a Stream[V] fn func(t T) (K, V, bool) c int } type testCase[T int, K int, V int] struct { name string args args[T, K, V] - wantR SimpleMapStream[K, V] + wantR MapStream[K, V] } tests := []testCase[int, int, int]{ { name: "t1", args: args[int, int, int]{ - a: NewSimpleSliceStream(x), + a: NewStream(x), fn: func(v int) (int, int, bool) { if v >= 50000 { return v, v, true @@ -555,8 +555,8 @@ func TestSimpleParallelFilterAndMapToMap(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if gotR := SimpleParallelFilterAndMapToMap(tt.args.a, tt.args.fn, tt.args.c); !reflect.DeepEqual(gotR, tt.wantR) { - t.Errorf("SimpleParallelFilterAndMapToMap() = %v, want %v", gotR, tt.wantR) + if gotR := ParallelFilterAndMapToMapStream(tt.args.a, tt.args.fn, tt.args.c); !reflect.DeepEqual(gotR, tt.wantR) { + t.Errorf("ParallelFilterAndMapToMapStream() = %v, want %v", gotR, tt.wantR) } }) } @@ -564,20 +564,20 @@ func TestSimpleParallelFilterAndMapToMap(t *testing.T) { func TestSimpleSliceFilterAndMapToMap(t *testing.T) { type args[T int, K int, V int] struct { - a SimpleSliceStream[T] + a Stream[T] fn func(t T) (K, V, bool) isCoverPrev bool } type testCase[T int, K int, V int] struct { name string args args[T, K, V] - wantR SimpleMapStream[K, V] + wantR MapStream[K, V] } tests := []testCase[int, int, int]{ { name: "t1", args: args[int, int, int]{ - a: NewSimpleSliceStream(number.Range(1, 10, 1)), + a: NewStream(number.Range(1, 10, 1)), fn: func(i int) (int, int, bool) { if i > 6 { return i, i, true @@ -592,8 +592,8 @@ func TestSimpleSliceFilterAndMapToMap(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if gotR := SimpleSliceFilterAndMapToMap(tt.args.a, tt.args.fn, tt.args.isCoverPrev); !reflect.DeepEqual(gotR, tt.wantR) { - t.Errorf("SimpleSliceFilterAndMapToMap() = %v, want %v", gotR, tt.wantR) + if gotR := SliceFilterAndMapToMapStream(tt.args.a, tt.args.fn, tt.args.isCoverPrev); !reflect.DeepEqual(gotR, tt.wantR) { + t.Errorf("SliceFilterAndMapToMapStream() = %v, want %v", gotR, tt.wantR) } }) }