diff --git a/arrutil/convert.go b/arrutil/convert.go index a9c85cad1..c0f98a6f4 100644 --- a/arrutil/convert.go +++ b/arrutil/convert.go @@ -3,7 +3,6 @@ package arrutil import ( "errors" "reflect" - "strconv" "strings" "github.com/gookit/goutil/comdef" @@ -84,30 +83,6 @@ func SliceToInt64s(arr []any) []int64 { return i64s } -// StringsAsInts convert and ignore error -func StringsAsInts(ss []string) []int { - ints, _ := StringsTryInts(ss) - return ints -} - -// StringsToInts string slice to int slice -func StringsToInts(ss []string) (ints []int, err error) { - return StringsTryInts(ss) -} - -// StringsTryInts string slice to int slice -func StringsTryInts(ss []string) (ints []int, err error) { - for _, str := range ss { - iVal, err := strconv.Atoi(str) - if err != nil { - return nil, err - } - - ints = append(ints, iVal) - } - return -} - // AnyToSlice convert any(allow: array,slice) to []any func AnyToSlice(sl any) (ls []any, err error) { rfKeys := reflect.ValueOf(sl) @@ -136,15 +111,6 @@ func MustToStrings(arr any) []string { return ret } -// StringsToSlice convert []string to []any -func StringsToSlice(ss []string) []any { - args := make([]any, len(ss)) - for i, s := range ss { - args[i] = s - } - return args -} - // ToStrings convert any(allow: array,slice) to []string func ToStrings(arr any) (ret []string, err error) { rv := reflect.ValueOf(arr) diff --git a/arrutil/convert_test.go b/arrutil/convert_test.go index c5a272d92..f40adc2d8 100644 --- a/arrutil/convert_test.go +++ b/arrutil/convert_test.go @@ -44,13 +44,15 @@ func TestToStrings(t *testing.T) { ss = arrutil.SliceToStrings([]any{1, 2}) is.Eq(`[]string{"1", "2"}`, fmt.Sprintf("%#v", ss)) - as := arrutil.StringsToSlice([]string{"1", "2"}) - is.Eq(`[]interface {}{"1", "2"}`, fmt.Sprintf("%#v", as)) - ss, err = arrutil.ToStrings("b") is.Nil(err) is.Eq(`[]string{"b"}`, fmt.Sprintf("%#v", ss)) + is.Empty(arrutil.AnyToStrings(234)) + is.Panics(func() { + arrutil.MustToStrings(234) + }) + _, err = arrutil.ToStrings([]any{[]int{1}, nil}) is.Err(err) } @@ -83,19 +85,12 @@ func TestSliceToString(t *testing.T) { is.Eq("[a,b]", arrutil.SliceToString("a", "b")) } -func TestStringsToInts(t *testing.T) { +func TestAnyToSlice(t *testing.T) { is := assert.New(t) - ints, err := arrutil.StringsToInts([]string{"1", "2"}) - is.Nil(err) - is.Eq("[]int{1, 2}", fmt.Sprintf("%#v", ints)) - - _, err = arrutil.StringsToInts([]string{"a", "b"}) - is.Err(err) - - ints = arrutil.StringsAsInts([]string{"1", "2"}) - is.Eq("[]int{1, 2}", fmt.Sprintf("%#v", ints)) - is.Nil(arrutil.StringsAsInts([]string{"abc"})) + sl, err := arrutil.AnyToSlice([]int{1, 2}) + is.NoErr(err) + is.Eq("[]interface {}{1, 2}", fmt.Sprintf("%#v", sl)) } func TestConvType(t *testing.T) { diff --git a/arrutil/format.go b/arrutil/format.go index d00b582a9..b549bcc55 100644 --- a/arrutil/format.go +++ b/arrutil/format.go @@ -15,7 +15,7 @@ type ArrFormatter struct { Prefix string // Indent string for format each element Indent string - // ClosePrefix string for last "]" + // ClosePrefix on before end char: ] ClosePrefix string } @@ -23,7 +23,6 @@ type ArrFormatter struct { func NewFormatter(arr any) *ArrFormatter { f := &ArrFormatter{} f.Src = arr - return f } @@ -47,7 +46,6 @@ func (f *ArrFormatter) FormatTo(w io.Writer) { // Format to string func (f *ArrFormatter) String() string { - f.Format() return f.Format() } diff --git a/arrutil/format_test.go b/arrutil/format_test.go index ab247128d..774273baa 100644 --- a/arrutil/format_test.go +++ b/arrutil/format_test.go @@ -1,6 +1,7 @@ package arrutil_test import ( + "bytes" "fmt" "testing" @@ -21,4 +22,18 @@ func TestNewFormatter(t *testing.T) { assert.Eq(t, "", arrutil.FormatIndent("invalid", "")) assert.Eq(t, "[]", arrutil.FormatIndent([]string{}, "")) + + sl := []string{"c", "d"} + f := arrutil.NewFormatter(sl) + f.WithFn(func(f *arrutil.ArrFormatter) { + f.Indent = " " + f.ClosePrefix = "-" + }) + str = f.String() + assert.Eq(t, "[\n c,\n d\n-]", str) + + f = arrutil.NewFormatter(sl) + w := &bytes.Buffer{} + f.FormatTo(w) + assert.Eq(t, "[c, d]", w.String()) } diff --git a/arrutil/ints.go b/arrutil/ints.go new file mode 100644 index 000000000..e60e4d8d1 --- /dev/null +++ b/arrutil/ints.go @@ -0,0 +1,26 @@ +package arrutil + +import ( + "strconv" + "strings" + + "github.com/gookit/goutil/comdef" +) + +// IntsToString convert []T to string +func IntsToString[T comdef.Integer](ints []T) string { + if len(ints) == 0 { + return "[]" + } + + var sb strings.Builder + sb.WriteByte('[') + for i, v := range ints { + if i > 0 { + sb.WriteByte(',') + } + sb.WriteString(strconv.FormatInt(int64(v), 10)) + } + sb.WriteByte(']') + return sb.String() +} diff --git a/arrutil/ints_test.go b/arrutil/ints_test.go new file mode 100644 index 000000000..d20cbf886 --- /dev/null +++ b/arrutil/ints_test.go @@ -0,0 +1,13 @@ +package arrutil_test + +import ( + "testing" + + "github.com/gookit/goutil/arrutil" + "github.com/gookit/goutil/testutil/assert" +) + +func TestIntsToString(t *testing.T) { + assert.Eq(t, "[]", arrutil.IntsToString([]int{})) + assert.Eq(t, "[1,2,3]", arrutil.IntsToString([]int{1, 2, 3})) +} diff --git a/arrutil/list.go b/arrutil/list.go index d4c290ee3..0acf25fe1 100644 --- a/arrutil/list.go +++ b/arrutil/list.go @@ -2,7 +2,6 @@ package arrutil import ( "sort" - "strconv" "strings" "github.com/gookit/goutil/comdef" @@ -13,11 +12,7 @@ type Ints []int // String to string func (is Ints) String() string { - ss := make([]string, len(is)) - for i, iv := range is { - ss[i] = strconv.Itoa(iv) - } - return strings.Join(ss, ",") + return ToString(is) } // Has given element @@ -84,7 +79,15 @@ func (ss Strings) First() string { if len(ss) > 0 { return ss[0] } - return "" + panic("empty string list") +} + +// Last element value. +func (ss Strings) Last() string { + if len(ss) > 0 { + return ss[len(ss)-1] + } + panic("empty string list") } // ScalarList definition for any type diff --git a/arrutil/list_test.go b/arrutil/list_test.go index 5e4aedee6..ea6f93e15 100644 --- a/arrutil/list_test.go +++ b/arrutil/list_test.go @@ -18,7 +18,7 @@ func TestInts_methods(t *testing.T) { arrutil.Ints{12, 23}, 12, true, - "12,23", + "[12,23]", }, } @@ -30,9 +30,19 @@ func TestInts_methods(t *testing.T) { ints := arrutil.Ints{23, 10, 12} ints.Sort() - assert.Eq(t, "10,12,23", ints.String()) + assert.Eq(t, "[10,12,23]", ints.String()) assert.Eq(t, 10, ints.First()) assert.Eq(t, 23, ints.Last()) + + t.Run("panic", func(t *testing.T) { + ints = arrutil.Ints{} + assert.Panics(t, func() { + ints.First() + }) + assert.Panics(t, func() { + ints.Last() + }) + }) } func TestStrings_methods(t *testing.T) { @@ -59,6 +69,17 @@ func TestStrings_methods(t *testing.T) { ss := arrutil.Strings{"a", "b"} assert.Eq(t, "a b", ss.Join(" ")) assert.Eq(t, "a", ss.First()) + assert.Eq(t, "b", ss.Last()) + + t.Run("panic", func(t *testing.T) { + ss = arrutil.Strings{} + assert.Panics(t, func() { + ss.First() + }) + assert.Panics(t, func() { + ss.Last() + }) + }) } func TestScalarList_methods(t *testing.T) { @@ -66,6 +87,7 @@ func TestScalarList_methods(t *testing.T) { 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()) diff --git a/arrutil/strings.go b/arrutil/strings.go new file mode 100644 index 000000000..920f54351 --- /dev/null +++ b/arrutil/strings.go @@ -0,0 +1,36 @@ +package arrutil + +import "strconv" + +// StringsToSlice convert []string to []any +func StringsToSlice(ss []string) []any { + args := make([]any, len(ss)) + for i, s := range ss { + args[i] = s + } + return args +} + +// StringsAsInts convert and ignore error +func StringsAsInts(ss []string) []int { + ints, _ := StringsTryInts(ss) + return ints +} + +// StringsToInts string slice to int slice +func StringsToInts(ss []string) (ints []int, err error) { + return StringsTryInts(ss) +} + +// StringsTryInts string slice to int slice +func StringsTryInts(ss []string) (ints []int, err error) { + for _, str := range ss { + iVal, err := strconv.Atoi(str) + if err != nil { + return nil, err + } + + ints = append(ints, iVal) + } + return +} diff --git a/arrutil/strings_test.go b/arrutil/strings_test.go new file mode 100644 index 000000000..20db707f1 --- /dev/null +++ b/arrutil/strings_test.go @@ -0,0 +1,31 @@ +package arrutil_test + +import ( + "fmt" + "testing" + + "github.com/gookit/goutil/arrutil" + "github.com/gookit/goutil/testutil/assert" +) + +func TestStringsToSlice(t *testing.T) { + is := assert.New(t) + + as := arrutil.StringsToSlice([]string{"1", "2"}) + is.Eq(`[]interface {}{"1", "2"}`, fmt.Sprintf("%#v", as)) +} + +func TestStringsToInts(t *testing.T) { + is := assert.New(t) + + ints, err := arrutil.StringsToInts([]string{"1", "2"}) + is.Nil(err) + is.Eq("[]int{1, 2}", fmt.Sprintf("%#v", ints)) + + _, err = arrutil.StringsToInts([]string{"a", "b"}) + is.Err(err) + + ints = arrutil.StringsAsInts([]string{"1", "2"}) + is.Eq("[]int{1, 2}", fmt.Sprintf("%#v", ints)) + is.Nil(arrutil.StringsAsInts([]string{"abc"})) +}