From a2695f4fcf2a266d3fc535d67d05d07259168d2f Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 5 Feb 2024 11:23:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=20stream=20=E5=8C=85?= =?UTF-8?q?=E5=AF=B9=E4=BA=8E=20[]string=20=E7=9A=84=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/stream/string.go | 8 +- utils/stream/string_test.go | 6 +- utils/stream/strings.go | 162 +++++++++++++++-------------------- utils/stream/strings_test.go | 90 +++++++++++++++++++ 4 files changed, 166 insertions(+), 100 deletions(-) diff --git a/utils/stream/string.go b/utils/stream/string.go index cc79616..e4446a0 100644 --- a/utils/stream/string.go +++ b/utils/stream/string.go @@ -15,7 +15,7 @@ type String[S ~string] struct { str S } -// Elem 返回字符串 +// Elem 返回原始元素 func (s *String[S]) Elem() S { return s.str } @@ -287,7 +287,7 @@ func (s *String[S]) Update(f func(S) S) *String[S] { } // Split 返回字符串切片 -func (s *String[S]) Split(sep string) Strings[S] { +func (s *String[S]) Split(sep string) *Strings[S] { slice := strings.Split(string(s.str), sep) rep := make([]S, len(slice)) for i, v := range slice { @@ -297,7 +297,7 @@ func (s *String[S]) Split(sep string) Strings[S] { } // SplitN 返回字符串切片 -func (s *String[S]) SplitN(sep string, n int) Strings[S] { +func (s *String[S]) SplitN(sep string, n int) *Strings[S] { slice := strings.SplitN(string(s.str), sep, n) rep := make([]S, len(slice)) for i, v := range slice { @@ -307,7 +307,7 @@ func (s *String[S]) SplitN(sep string, n int) Strings[S] { } // Batched 将字符串按照指定长度分组,最后一组可能小于指定长度 -func (s *String[S]) Batched(size int) Strings[S] { +func (s *String[S]) Batched(size int) *Strings[S] { var str = string(s.str) var result = make([]S, 0, len(str)/size+1) for len(str) >= size { diff --git a/utils/stream/string_test.go b/utils/stream/string_test.go index 331c7ad..9e0fb08 100644 --- a/utils/stream/string_test.go +++ b/utils/stream/string_test.go @@ -767,7 +767,7 @@ func TestString_Split(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { got := stream.NewString(c.in).Split(c.sep) - for i, v := range got { + for i, v := range got.Elem() { if v != c.want[i] { t.Fatalf("NewString(%s).Split(%s) = %v; want %v", c.in, c.sep, got, c.want) } @@ -791,7 +791,7 @@ func TestString_SplitN(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { got := stream.NewString(c.in).SplitN(c.sep, c.n) - for i, v := range got { + for i, v := range got.Elem() { if v != c.want[i] { t.Fatalf("NewString(%s).SplitN(%s, %d) = %v; want %v", c.in, c.sep, c.n, got, c.want) } @@ -814,7 +814,7 @@ func TestString_Batched(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { got := stream.NewString(c.in).Batched(c.size) - for i, v := range got { + for i, v := range got.Elem() { if v != c.want[i] { t.Fatalf("NewString(%s).Batched(%d) = %v; want %v", c.in, c.size, got, c.want) } diff --git a/utils/stream/strings.go b/utils/stream/strings.go index 981e04f..9551d2f 100644 --- a/utils/stream/strings.go +++ b/utils/stream/strings.go @@ -1,123 +1,99 @@ package stream -import ( - "sort" -) +import "strings" // NewStrings 创建字符串切片 -func NewStrings[S ~string](s ...S) Strings[S] { - var slice = make(Strings[S], len(s)) - for i, v := range s { - slice[i] = v - } - return slice +func NewStrings[S ~string](s ...S) *Strings[S] { + return &Strings[S]{s} } // Strings 字符串切片 -type Strings[S ~string] []S +type Strings[S ~string] struct { + s []S +} + +// Elem 返回原始元素 +func (s *Strings[S]) Elem() []S { + return s.s +} // Len 返回切片长度 func (s *Strings[S]) Len() int { - return len(*s) + return len(s.s) } // Append 添加字符串 func (s *Strings[S]) Append(ss ...S) *Strings[S] { - *s = append(*s, NewStrings(ss...)...) + s.s = append(s.s, ss...) return s } -// Clear 清空切片 -func (s *Strings[S]) Clear() *Strings[S] { - *s = make(Strings[S], 0) - return s -} - -// Copy 复制切片 -func (s *Strings[S]) Copy() *Strings[S] { - ss := make(Strings[S], len(*s)) - copy(ss, *s) - return &ss -} - -// Range 返回指定范围的切片 -func (s *Strings[S]) Range(start, end int) *Strings[S] { - *s = (*s)[start:end] - return s -} - -// First 返回第一个元素 -func (s *Strings[S]) First() *String[S] { - return NewString((*s)[0]) -} - -// Last 返回最后一个元素 -func (s *Strings[S]) Last() *String[S] { - return NewString((*s)[len(*s)-1]) -} - -// Index 返回指定的元素 -func (s *Strings[S]) Index(i int) *String[S] { - return NewString((*s)[i]) -} - -// Reverse 反转切片 -func (s *Strings[S]) Reverse() *Strings[S] { - for i, j := 0, len(*s)-1; i < j; i, j = i+1, j-1 { - (*s)[i], (*s)[j] = (*s)[j], (*s)[i] +// Join 连接字符串 +func (s *Strings[S]) Join(sep S) *String[S] { + var cast = make([]string, len(s.s)) + for i, v := range s.s { + cast[i] = string(v) } - return s + return NewString(S(strings.Join(cast, string(sep)))) } -// Desc 降序排序 -func (s *Strings[S]) Desc() *Strings[S] { - sort.Slice(*s, func(i, j int) bool { - return (*s)[i] > (*s)[j] - }) - return s +// Choice 选择字符串 +func (s *Strings[S]) Choice(i int) *String[S] { + return NewString(s.s[i]) } -// Asc 升序排序 -func (s *Strings[S]) Asc() *Strings[S] { - sort.Slice(*s, func(i, j int) bool { - return (*s)[i] < (*s)[j] - }) - return s -} - -// Sort 自定义排序 -func (s *Strings[S]) Sort(f func(int, int) bool) *Strings[S] { - sort.Slice(*s, func(i, j int) bool { - return f(i, j) - }) - return s -} - -// Unique 去重 -func (s *Strings[S]) Unique() *Strings[S] { - m := map[S]struct{}{} - for _, v := range *s { - m[v] = struct{}{} - } - *s = make(Strings[S], 0, len(m)) - for k := range m { - *s = append(*s, k) +// Choices 选择多个字符串 +func (s *Strings[S]) Choices(i ...int) *Strings[S] { + var ss = make([]S, len(i)) + for j, v := range i { + ss[j] = s.s[v] } + return NewStrings(ss...) +} + +// ChoiceInRange 选择范围内的字符串 +func (s *Strings[S]) ChoiceInRange(start, end int) *Strings[S] { + return NewStrings(s.s[start:end]...) +} + +// Remove 移除字符串 +func (s *Strings[S]) Remove(i int) *Strings[S] { + s.s = append(s.s[:i], s.s[i+1:]...) return s } -// Delete 删除指定位置的字符串 -func (s *Strings[S]) Delete(i int) *Strings[S] { - *s = append((*s)[:i], (*s)[i+1:]...) - return s -} - -// Each 遍历切片 -func (s *Strings[S]) Each(f func(int, S) bool) *Strings[S] { - for i, v := range *s { - if !f(i, v) { - break +// Removes 移除多个字符串 +func (s *Strings[S]) Removes(i ...int) *Strings[S] { + var ss = make([]S, 0, len(s.s)-len(i)) + for j, v := range s.s { + for _, i := range i { + if j != i { + ss = append(ss, v) + } } } + s.s = ss return s } + +// RemoveInRange 移除范围内的字符串 +func (s *Strings[S]) RemoveInRange(start, end int) *Strings[S] { + s.s = append(s.s[:start], s.s[end:]...) + return s +} + +// Clear 清空字符串 +func (s *Strings[S]) Clear() *Strings[S] { + s.s = []S{} + return s +} + +// First 第一个字符串 +func (s *Strings[S]) First() *String[S] { + return NewString(s.s[0]) +} + +// Last 最后一个字符串 +func (s *Strings[S]) Last() *String[S] { + return NewString(s.s[len(s.s)-1]) +} diff --git a/utils/stream/strings_test.go b/utils/stream/strings_test.go index 8d4d002..fb9d9d2 100644 --- a/utils/stream/strings_test.go +++ b/utils/stream/strings_test.go @@ -1 +1,91 @@ package stream_test + +import ( + "github.com/kercylan98/minotaur/utils/stream" + "testing" +) + +func TestNewStrings(t *testing.T) { + var cases = []struct { + name string + in []string + want []string + }{ + {name: "empty", in: []string{}, want: []string{}}, + {name: "one", in: []string{"a"}, want: []string{"a"}}, + {name: "two", in: []string{"a", "b"}, want: []string{"a", "b"}}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := stream.NewStrings(c.in...) + if got.Len() != len(c.want) { + t.Errorf("got %v, want %v", got, c.want) + } + }) + } +} + +func TestStrings_Elem(t *testing.T) { + var cases = []struct { + name string + in []string + want []string + }{ + {name: "empty", in: []string{}, want: []string{}}, + {name: "one", in: []string{"a"}, want: []string{"a"}}, + {name: "two", in: []string{"a", "b"}, want: []string{"a", "b"}}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := stream.NewStrings(c.in...).Elem() + if len(got) != len(c.want) { + t.Errorf("got %v, want %v", got, c.want) + } + }) + } +} + +func TestStrings_Len(t *testing.T) { + var cases = []struct { + name string + in []string + want int + }{ + {name: "empty", in: []string{}, want: 0}, + {name: "one", in: []string{"a"}, want: 1}, + {name: "two", in: []string{"a", "b"}, want: 2}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := stream.NewStrings(c.in...) + if got.Len() != c.want { + t.Errorf("got %v, want %v", got, c.want) + } + }) + } +} + +func TestStrings_Append(t *testing.T) { + var cases = []struct { + name string + in []string + append []string + want []string + }{ + {name: "empty", in: []string{}, append: []string{"a"}, want: []string{"a"}}, + {name: "one", in: []string{"a"}, append: []string{"b"}, want: []string{"a", "b"}}, + {name: "two", in: []string{"a", "b"}, append: []string{"c"}, want: []string{"a", "b", "c"}}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := stream.NewStrings(c.in...).Append(c.append...) + if got.Len() != len(c.want) { + t.Errorf("got %v, want %v", got, c.want) + } + }) + } +}