From fe184cf1f02b2c0024006fb76dcdf429a84baa24 Mon Sep 17 00:00:00 2001 From: Inhere Date: Wed, 5 Jul 2023 12:56:55 +0800 Subject: [PATCH] :sparkles: feat: arrutil - enhance the Ints and Strings and SortedList --- arrutil/list.go | 109 +++++++++++++++++++++++++++++--------- arrutil/list_test.go | 50 +++++++++-------- comdef/types.go | 2 +- fsutil/finder/matchers.go | 6 +-- 4 files changed, 112 insertions(+), 55 deletions(-) diff --git a/arrutil/list.go b/arrutil/list.go index 0acf25fe1..2c938c19d 100644 --- a/arrutil/list.go +++ b/arrutil/list.go @@ -8,15 +8,15 @@ import ( ) // Ints type -type Ints []int +type Ints[T comdef.Integer] []T // String to string -func (is Ints) String() string { +func (is Ints[T]) String() string { return ToString(is) } // Has given element -func (is Ints) Has(i int) bool { +func (is Ints[T]) Has(i T) bool { for _, iv := range is { if i == iv { return true @@ -26,24 +26,47 @@ func (is Ints) Has(i int) bool { } // First element value. -func (is Ints) First() int { +func (is Ints[T]) First(defVal ...T) T { if len(is) > 0 { return is[0] } - panic("empty int slice") + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty integer slice") } // Last element value. -func (is Ints) Last() int { +func (is Ints[T]) Last(defVal ...T) T { if len(is) > 0 { return is[len(is)-1] } - panic("empty int slice") + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty integer slice") } // Sort the int slice -func (is Ints) Sort() { - sort.Ints(is) +func (is Ints[T]) Sort() { + sort.Sort(is) +} + +// Len get length +func (is Ints[T]) Len() int { + return len(is) +} + +// Less compare two elements +func (is Ints[T]) Less(i, j int) bool { + return is[i] < is[j] +} + +// Swap elements by indexes +func (is Ints[T]) Swap(i, j int) { + is[i], is[j] = is[j], is[i] } // Strings type @@ -75,41 +98,69 @@ func (ss Strings) Contains(sub string) bool { } // First element value. -func (ss Strings) First() string { +func (ss Strings) First(defVal ...string) string { if len(ss) > 0 { return ss[0] } + + if len(defVal) > 0 { + return defVal[0] + } panic("empty string list") } // Last element value. -func (ss Strings) Last() string { +func (ss Strings) Last(defVal ...string) string { if len(ss) > 0 { return ss[len(ss)-1] } + + if len(defVal) > 0 { + return defVal[0] + } panic("empty string list") } -// ScalarList definition for any type -type ScalarList[T comdef.ScalarType] []T +// Sort the string slice +func (ss Strings) Sort() { + sort.Strings(ss) +} + +// SortedList definition for compared type +type SortedList[T comdef.Compared] []T + +// Len get length +func (ls SortedList[T]) Len() int { + return len(ls) +} + +// Less compare two elements +func (ls SortedList[T]) Less(i, j int) bool { + return ls[i] < ls[j] +} + +// Swap elements by indexes +func (ls SortedList[T]) Swap(i, j int) { + ls[i], ls[j] = ls[j], ls[i] +} // IsEmpty check -func (ls ScalarList[T]) IsEmpty() bool { +func (ls SortedList[T]) IsEmpty() bool { return len(ls) == 0 } // String to string -func (ls ScalarList[T]) String() string { +func (ls SortedList[T]) String() string { return ToString(ls) } // Has given element -func (ls ScalarList[T]) Has(el T) bool { +func (ls SortedList[T]) Has(el T) bool { return ls.Contains(el) } // Contains given element -func (ls ScalarList[T]) Contains(el T) bool { +func (ls SortedList[T]) Contains(el T) bool { for _, v := range ls { if v == el { return true @@ -119,39 +170,47 @@ func (ls ScalarList[T]) Contains(el T) bool { } // First element value. -func (ls ScalarList[T]) First() T { +func (ls SortedList[T]) First(defVal ...T) T { if len(ls) > 0 { return ls[0] } + + if len(defVal) > 0 { + return defVal[0] + } panic("empty list") } // Last element value. -func (ls ScalarList[T]) Last() T { +func (ls SortedList[T]) Last(defVal ...T) T { if ln := len(ls); ln > 0 { return ls[ln-1] } + + if len(defVal) > 0 { + return defVal[0] + } panic("empty list") } // Remove given element -func (ls ScalarList[T]) Remove(el T) ScalarList[T] { +func (ls SortedList[T]) Remove(el T) SortedList[T] { return Filter(ls, func(v T) bool { return v != el }) } // Filter the slice, default will filter zero value. -func (ls ScalarList[T]) Filter(filter ...comdef.MatchFunc[T]) ScalarList[T] { +func (ls SortedList[T]) Filter(filter ...comdef.MatchFunc[T]) SortedList[T] { return Filter(ls, filter...) } // Map the slice to new slice. TODO syntax ERROR: Method cannot have type parameters -// func (ls ScalarList[T]) Map[V any](mapFn MapFn[T, V]) ScalarList[V] { +// func (ls SortedList[T]) Map[V any](mapFn MapFn[T, V]) SortedList[V] { // return Map(ls, mapFn) // } // Sort the slice -// func (ls ScalarList[T]) Sort() { -// sort.Sort(ls) -// } +func (ls SortedList[T]) Sort() { + sort.Sort(ls) +} diff --git a/arrutil/list_test.go b/arrutil/list_test.go index ea6f93e15..cdd52babf 100644 --- a/arrutil/list_test.go +++ b/arrutil/list_test.go @@ -8,34 +8,20 @@ import ( ) func TestInts_methods(t *testing.T) { - tests := []struct { - is arrutil.Ints - val int - want bool - want2 string - }{ - { - arrutil.Ints{12, 23}, - 12, - true, - "[12,23]", - }, - } + ints := arrutil.Ints[int]{23, 10, 12} + assert.False(t, ints.Has(999)) + assert.Eq(t, "[23,10,12]", ints.String()) - for _, tt := range tests { - assert.Eq(t, tt.want, tt.is.Has(tt.val)) - assert.False(t, tt.is.Has(999)) - assert.Eq(t, tt.want2, tt.is.String()) - } - - ints := arrutil.Ints{23, 10, 12} ints.Sort() assert.Eq(t, "[10,12,23]", ints.String()) assert.Eq(t, 10, ints.First()) assert.Eq(t, 23, ints.Last()) + ints = arrutil.Ints[int]{} + assert.Eq(t, 1, ints.First(1)) + assert.Eq(t, 2, ints.Last(2)) + t.Run("panic", func(t *testing.T) { - ints = arrutil.Ints{} assert.Panics(t, func() { ints.First() }) @@ -71,8 +57,11 @@ func TestStrings_methods(t *testing.T) { assert.Eq(t, "a", ss.First()) assert.Eq(t, "b", ss.Last()) + ss = arrutil.Strings{} + assert.Eq(t, "default1", ss.First("default1")) + assert.Eq(t, "default2", ss.Last("default2")) + t.Run("panic", func(t *testing.T) { - ss = arrutil.Strings{} assert.Panics(t, func() { ss.First() }) @@ -82,18 +71,27 @@ func TestStrings_methods(t *testing.T) { }) } -func TestScalarList_methods(t *testing.T) { - ls := arrutil.ScalarList[string]{"a", "", "b"} +func TestSortedList_methods(t *testing.T) { + ls := arrutil.SortedList[string]{"a", "", "b"} assert.Eq(t, "a", ls.First()) assert.Eq(t, "b", ls.Last()) assert.True(t, ls.Has("a")) assert.False(t, ls.Has("e")) assert.False(t, ls.IsEmpty()) assert.Eq(t, "[a,b]", ls.Filter().String()) - assert.Eq(t, "[a,b]", ls.Remove("").String()) + + ls = ls.Remove("") + assert.Eq(t, "[a,b]", ls.String()) + + ls1 := arrutil.SortedList[int]{4, 3} + ls1.Sort() + assert.Eq(t, "[3,4]", ls1.String()) + + ls = arrutil.SortedList[string]{} + assert.Eq(t, "default1", ls.First("default1")) + assert.Eq(t, "default2", ls.Last("default2")) t.Run("panic", func(t *testing.T) { - ls = arrutil.ScalarList[string]{} assert.Panics(t, func() { ls.First() }) diff --git a/comdef/types.go b/comdef/types.go index 21a1ebfea..d180f0315 100644 --- a/comdef/types.go +++ b/comdef/types.go @@ -61,7 +61,7 @@ type SimpleType interface { // ScalarType interface type. // -// it can be ordered, that supports the operators < <= >= >. +// TIP: has bool type, it cannot be ordered // // contains: (x)int, float, ~string, ~bool types type ScalarType interface { diff --git a/fsutil/finder/matchers.go b/fsutil/finder/matchers.go index fc17975f3..5db69dcf2 100644 --- a/fsutil/finder/matchers.go +++ b/fsutil/finder/matchers.go @@ -239,9 +239,9 @@ var timeNumReg = regexp.MustCompile(`(-?\d+)`) // // Usage: // -// f := EmptyFinder() -// f.AddFilter(HumanModTime(">10m")) // before 10 minutes -// f.AddFilter(HumanModTime("<10m")) // latest 10 minutes, to Now +// f := finder.NewFinder() +// f.Include(HumanModTime(">10m")) // before 10 minutes +// f.Include(HumanModTime("<10m")) // latest 10 minutes, to Now func HumanModTime(expr string) MatcherFunc { opt := &timex.ParseRangeOpt{AutoSort: true} // convert > to <, < to >