Bump github.com/gookit/config/v2 from 2.2.3 to 2.2.4

Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/gookit/config/releases)
- [Commits](https://github.com/gookit/config/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: github.com/gookit/config/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-11-03 10:26:28 +01:00
committed by Ralf Haferkamp
parent 30784affc4
commit 0df009eae0
141 changed files with 7314 additions and 4044 deletions
-114
View File
@@ -2,95 +2,9 @@
package arrutil
import (
"strings"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/mathutil"
)
// Reverse string slice [site user info 0] -> [0 info user site]
func Reverse(ss []string) {
ln := len(ss)
for i := 0; i < ln/2; i++ {
li := ln - i - 1
ss[i], ss[li] = ss[li], ss[i]
}
}
// StringsRemove a value form a string slice
func StringsRemove(ss []string, s string) []string {
ns := make([]string, 0, len(ss))
for _, v := range ss {
if v != s {
ns = append(ns, v)
}
}
return ns
}
// StringsFilter given strings, default will filter emtpy string.
//
// Usage:
//
// // output: [a, b]
// ss := arrutil.StringsFilter([]string{"a", "", "b", ""})
func StringsFilter(ss []string, filter ...func(s string) bool) []string {
var fn func(s string) bool
if len(filter) > 0 && filter[0] != nil {
fn = filter[0]
} else {
fn = func(s string) bool {
return s != ""
}
}
ns := make([]string, 0, len(ss))
for _, s := range ss {
if fn(s) {
ns = append(ns, s)
}
}
return ns
}
// StringsMap handle each string item, map to new strings
func StringsMap(ss []string, mapFn func(s string) string) []string {
ns := make([]string, 0, len(ss))
for _, s := range ss {
ns = append(ns, mapFn(s))
}
return ns
}
// TrimStrings trim string slice item.
//
// Usage:
//
// // output: [a, b, c]
// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.")
func TrimStrings(ss []string, cutSet ...string) []string {
cutSetLn := len(cutSet)
hasCutSet := cutSetLn > 0 && cutSet[0] != ""
var trimSet string
if hasCutSet {
trimSet = cutSet[0]
}
if cutSetLn > 1 {
trimSet = strings.Join(cutSet, "")
}
ns := make([]string, 0, len(ss))
for _, str := range ss {
if hasCutSet {
ns = append(ns, strings.Trim(str, trimSet))
} else {
ns = append(ns, strings.TrimSpace(str))
}
}
return ns
}
// GetRandomOne get random element from an array/slice
func GetRandomOne[T any](arr []T) T { return RandomOne(arr) }
@@ -102,31 +16,3 @@ func RandomOne[T any](arr []T) T {
}
panic("cannot get value from nil or empty slice")
}
// Unique value in the given slice data.
func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
if len(list) < 2 {
return list
}
valMap := make(map[T]struct{}, len(list))
uniArr := make([]T, 0, len(list))
for _, t := range list {
if _, ok := valMap[t]; !ok {
valMap[t] = struct{}{}
uniArr = append(uniArr, t)
}
}
return uniArr
}
// IndexOf value in given slice.
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
for i, v := range list {
if v == val {
return i
}
}
return -1
}
+18 -6
View File
@@ -8,8 +8,18 @@ import (
"github.com/gookit/goutil/mathutil"
)
// IntsHas check the []int contains the given value
func IntsHas(ints []int, val int) bool {
// SliceHas check the slice contains the given value
func SliceHas[T comdef.ScalarType](slice []T, val T) bool {
for _, ele := range slice {
if ele == val {
return true
}
}
return false
}
// IntsHas check the []comdef.Integer contains the given value
func IntsHas[T comdef.Integer](ints []T, val T) bool {
for _, ele := range ints {
if ele == val {
return true
@@ -28,11 +38,8 @@ func Int64sHas(ints []int64, val int64) bool {
return false
}
// InStrings alias of StringsHas()
func InStrings(elem string, ss []string) bool { return StringsHas(ss, elem) }
// StringsHas check the []string contains the given element
func StringsHas(ss []string, val string) bool {
func StringsHas[T ~string](ss []T, val T) bool {
for _, ele := range ss {
if ele == val {
return true
@@ -41,6 +48,11 @@ func StringsHas(ss []string, val string) bool {
return false
}
// InStrings check elem in the ss. alias of StringsHas()
func InStrings[T ~string](elem T, ss []T) bool {
return StringsHas(ss, elem)
}
// NotIn check the given value whether not in the list
func NotIn[T comdef.ScalarType](value T, list []T) bool {
return !In(value, list)
+198 -266
View File
@@ -2,97 +2,72 @@ package arrutil
import (
"errors"
"reflect"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/reflects"
)
// ErrElementNotFound is the error returned when the element is not found.
const ErrElementNotFound = "element not found"
var ErrElementNotFound = errors.New("element not found")
// Comparer Function to compare two elements.
type Comparer func(a, b any) int
type Comparer[T any] func(a, b T) int
// type Comparer func(a, b any) int
// Predicate Function to predicate a struct/value satisfies a condition.
type Predicate func(a any) bool
type Predicate[T any] func(v T) bool
var (
// StringEqualsComparer Comparer for string. It will compare the string by their value.
// returns: 0 if equal, -1 if a != b
StringEqualsComparer Comparer = func(a, b any) int {
typeOfA := reflect.TypeOf(a)
if typeOfA.Kind() == reflect.Ptr {
typeOfA = typeOfA.Elem()
}
typeOfB := reflect.TypeOf(b)
if typeOfB.Kind() == reflect.Ptr {
typeOfB = typeOfB.Elem()
}
if typeOfA != typeOfB {
return -1
}
strA := ""
strB := ""
if val, ok := a.(string); ok {
strA = val
} else if val, ok := a.(*string); ok {
strA = *val
} else {
return -1
}
if val, ok := b.(string); ok {
strB = val
} else if val, ok := b.(*string); ok {
strB = *val
} else {
return -1
}
if strA == strB {
return 0
}
return -1
}
// ReferenceEqualsComparer Comparer for strcut ptr. It will compare the struct by their ptr addr.
// returns: 0 if equal, -1 if a != b
ReferenceEqualsComparer Comparer = func(a, b any) int {
if a == b {
return 0
}
return -1
}
// ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type (reflect.Type.Elem()).
// returns: 0 if same type, -1 if not.
ElemTypeEqualsComparer Comparer = func(a, b any) int {
at := reflect.TypeOf(a)
bt := reflect.TypeOf(b)
if at.Kind() == reflect.Ptr {
at = at.Elem()
}
if bt.Kind() == reflect.Ptr {
bt = bt.Elem()
}
if at == bt {
return 0
}
return -1
}
)
// TwowaySearch Find specialized element in a slice forward and backward in the same time, should be more quickly.
// StringEqualsComparer Comparer for string. It will compare the string by their value.
//
// data: the slice to search in. MUST BE A SLICE.
// item: the element to search.
// fn: the comparer function.
// return: the index of the element, or -1 if not found.
func TwowaySearch(data any, item any, fn Comparer) (int, error) {
// returns: 0 if equal, -1 if a != b
func StringEqualsComparer(a, b string) int {
if a == b {
return 0
}
return -1
}
// ValueEqualsComparer Comparer for comdef.Compared type. It will compare by their value.
//
// returns: 0 if equal, -1 if a != b
func ValueEqualsComparer[T comdef.Compared](a, b T) int {
if a == b {
return 0
}
return -1
}
// ReflectEqualsComparer Comparer for struct ptr. It will compare by reflect.Value
//
// returns: 0 if equal, -1 if a != b
func ReflectEqualsComparer[T any](a, b T) int {
if reflects.IsEqual(a, b) {
return 0
}
return -1
}
// ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type.
//
// returns: 0 if same type, -1 if not.
func ElemTypeEqualsComparer[T any](a, b T) int {
at := reflects.TypeOf(a).SafeElem()
bt := reflects.TypeOf(b).SafeElem()
if at == bt {
return 0
}
return -1
}
// TwowaySearch find specialized element in a slice forward and backward in the same time, should be more quickly.
//
// - data: the slice to search in. MUST BE A SLICE.
// - item: the element to search.
// - fn: the comparer function.
// - return: the index of the element, or -1 if not found.
func TwowaySearch[T any](data []T, item T, fn Comparer[T]) (int, error) {
if data == nil {
return -1, errors.New("collections.TwowaySearch: data is nil")
}
@@ -100,35 +75,19 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) {
return -1, errors.New("collections.TwowaySearch: fn is nil")
}
dataType := reflect.TypeOf(data)
if dataType.Kind() != reflect.Slice {
return -1, errors.New("collections.TwowaySearch: data is not a slice")
}
dataVal := reflect.ValueOf(data)
if dataVal.Len() == 0 {
if len(data) == 0 {
return -1, errors.New("collections.TwowaySearch: data is empty")
}
itemType := dataType.Elem()
if itemType.Kind() == reflect.Ptr {
itemType = itemType.Elem()
}
if itemType != dataVal.Index(0).Type() {
return -1, errors.New("collections.TwowaySearch: item type is not the same as data type")
}
forward := 0
backward := dataVal.Len() - 1
backward := len(data) - 1
for forward <= backward {
forwardVal := dataVal.Index(forward).Interface()
if fn(forwardVal, item) == 0 {
if fn(data[forward], item) == 0 {
return forward, nil
}
backwardVal := dataVal.Index(backward).Interface()
if fn(backwardVal, item) == 0 {
if fn(data[backward], item) == 0 {
return backward, nil
}
@@ -136,55 +95,44 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) {
backward--
}
return -1, errors.New(ErrElementNotFound)
}
// MakeEmptySlice Create a new slice with the elements of the source that satisfy the predicate.
//
// itemType: the type of the elements in the source.
// returns: the new slice.
func MakeEmptySlice(itemType reflect.Type) any {
ret := reflect.MakeSlice(reflect.SliceOf(itemType), 0, 0).Interface()
return ret
return -1, ErrElementNotFound
}
// CloneSlice Clone a slice.
//
// data: the slice to clone.
// returns: the cloned slice.
func CloneSlice(data any) any {
typeOfData := reflect.TypeOf(data)
if typeOfData.Kind() != reflect.Slice {
panic("collections.CloneSlice: data must be a slice")
}
return reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfData.Elem())).Elem(), reflect.ValueOf(data)).Interface()
func CloneSlice[T any](data []T) []T {
nt := make([]T, 0, len(data))
nt = append(nt, data...)
return nt
}
// Diff Produces the set difference of two slice according to a comparer function. alias of Differences
func Diff[T any](first, second []T, fn Comparer[T]) []T {
return Differences(first, second, fn)
}
// Differences Produces the set difference of two slice according to a comparer function.
//
// first: the first slice. MUST BE A SLICE.
// second: the second slice. MUST BE A SLICE.
// fn: the comparer function.
// returns: the difference of the two slices.
func Differences[T any](first, second []T, fn Comparer) []T {
typeOfFirst := reflect.TypeOf(first)
if typeOfFirst.Kind() != reflect.Slice {
panic("collections.Excepts: first must be a slice")
}
typeOfSecond := reflect.TypeOf(second)
if typeOfSecond.Kind() != reflect.Slice {
panic("collections.Excepts: second must be a slice")
}
// - first: the first slice. MUST BE A SLICE.
// - second: the second slice. MUST BE A SLICE.
// - fn: the comparer function.
// - returns: the difference of the two slices.
//
// Example:
//
// // Output: []string{"c"}
// Differences([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer
func Differences[T any](first, second []T, fn Comparer[T]) []T {
firstLen := len(first)
if firstLen == 0 {
return CloneSlice(second).([]T)
return CloneSlice(second)
}
secondLen := len(second)
if secondLen == 0 {
return CloneSlice(first).([]T)
return CloneSlice(first)
}
max := firstLen
@@ -214,139 +162,123 @@ func Differences[T any](first, second []T, fn Comparer) []T {
// Excepts Produces the set difference of two slice according to a comparer function.
//
// first: the first slice. MUST BE A SLICE.
// second: the second slice. MUST BE A SLICE.
// fn: the comparer function.
// returns: the difference of the two slices.
func Excepts(first, second any, fn Comparer) any {
typeOfFirst := reflect.TypeOf(first)
if typeOfFirst.Kind() != reflect.Slice {
panic("collections.Excepts: first must be a slice")
// - first: the first slice. MUST BE A SLICE.
// - second: the second slice. MUST BE A SLICE.
// - fn: the comparer function.
// - returns: the difference of the two slices.
//
// Example:
//
// // Output: []string{"c"}
// Excepts([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer)
func Excepts[T any](first, second []T, fn Comparer[T]) []T {
if len(first) == 0 {
return make([]T, 0)
}
valOfFirst := reflect.ValueOf(first)
if valOfFirst.Len() == 0 {
return MakeEmptySlice(typeOfFirst.Elem())
}
typeOfSecond := reflect.TypeOf(second)
if typeOfSecond.Kind() != reflect.Slice {
panic("collections.Excepts: second must be a slice")
}
valOfSecond := reflect.ValueOf(second)
if valOfSecond.Len() == 0 {
if len(second) == 0 {
return CloneSlice(first)
}
result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem()
for i := 0; i < valOfFirst.Len(); i++ {
s := valOfFirst.Index(i).Interface()
result := make([]T, 0)
for _, s := range first {
if i, _ := TwowaySearch(second, s, fn); i < 0 {
result = reflect.Append(result, reflect.ValueOf(s))
result = append(result, s)
}
}
return result.Interface()
return result
}
// Intersects Produces to intersect of two slice according to a comparer function.
//
// first: the first slice. MUST BE A SLICE.
// second: the second slice. MUST BE A SLICE.
// fn: the comparer function.
// returns: to intersect of the two slices.
func Intersects(first any, second any, fn Comparer) any {
typeOfFirst := reflect.TypeOf(first)
if typeOfFirst.Kind() != reflect.Slice {
panic("collections.Intersects: first must be a slice")
}
valOfFirst := reflect.ValueOf(first)
if valOfFirst.Len() == 0 {
return MakeEmptySlice(typeOfFirst.Elem())
// - first: the first slice. MUST BE A SLICE.
// - second: the second slice. MUST BE A SLICE.
// - fn: the comparer function.
// - returns: to intersect of the two slices.
//
// Example:
//
// // Output: []string{"a", "b"}
// Intersects([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer)
func Intersects[T any](first, second []T, fn Comparer[T]) []T {
if len(first) == 0 || len(second) == 0 {
return make([]T, 0)
}
typeOfSecond := reflect.TypeOf(second)
if typeOfSecond.Kind() != reflect.Slice {
panic("collections.Intersects: second must be a slice")
}
valOfSecond := reflect.ValueOf(second)
if valOfSecond.Len() == 0 {
return MakeEmptySlice(typeOfFirst.Elem())
}
result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem()
for i := 0; i < valOfFirst.Len(); i++ {
s := valOfFirst.Index(i).Interface()
result := make([]T, 0)
for _, s := range first {
if i, _ := TwowaySearch(second, s, fn); i >= 0 {
result = reflect.Append(result, reflect.ValueOf(s))
result = append(result, s)
}
}
return result.Interface()
return result
}
// Union Produces the set union of two slice according to a comparer function
//
// first: the first slice. MUST BE A SLICE.
// second: the second slice. MUST BE A SLICE.
// fn: the comparer function.
// returns: the union of the two slices.
func Union(first, second any, fn Comparer) any {
excepts := Excepts(second, first, fn)
typeOfFirst := reflect.TypeOf(first)
if typeOfFirst.Kind() != reflect.Slice {
panic("collections.Intersects: first must be a slice")
}
valOfFirst := reflect.ValueOf(first)
if valOfFirst.Len() == 0 {
// - first: the first slice. MUST BE A SLICE.
// - second: the second slice. MUST BE A SLICE.
// - fn: the comparer function.
// - returns: the union of the two slices.
//
// Example:
//
// // Output: []string{"a", "b", "c"}
// sl := Union([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer)
func Union[T any](first, second []T, fn Comparer[T]) []T {
if len(first) == 0 {
return CloneSlice(second)
}
result := reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem(), valOfFirst)
result = reflect.AppendSlice(result, reflect.ValueOf(excepts))
return result.Interface()
excepts := Excepts(second, first, fn)
nt := make([]T, 0, len(first)+len(second))
nt = append(nt, first...)
return append(nt, excepts...)
}
// Find Produces the struct/value of a slice according to a predicate function.
// Find Produces the value of a slice according to a predicate function.
//
// source: the slice. MUST BE A SLICE.
// fn: the predicate function.
// returns: the struct/value of the slice.
func Find(source any, fn Predicate) (any, error) {
aType := reflect.TypeOf(source)
if aType.Kind() != reflect.Slice {
panic("collections.Find: source must be a slice")
// - source: the slice. MUST BE A SLICE.
// - fn: the predicate function.
// - returns: the struct/value of the slice.
//
// Example:
//
// // Output: "c"
// val := Find([]string{"a", "b", "c"}, func(s string) bool {
// return s == "c"
// })
func Find[T any](source []T, fn Predicate[T]) (v T, err error) {
err = ErrElementNotFound
if len(source) == 0 {
return
}
sourceVal := reflect.ValueOf(source)
if sourceVal.Len() == 0 {
return nil, errors.New(ErrElementNotFound)
}
for i := 0; i < sourceVal.Len(); i++ {
s := sourceVal.Index(i).Interface()
for _, s := range source {
if fn(s) {
return s, nil
}
}
return nil, errors.New(ErrElementNotFound)
return
}
// FindOrDefault Produce the struct/value f a slice to a predicate function,
// FindOrDefault Produce the value f a slice to a predicate function,
// Produce default value when predicate function not found.
//
// source: the slice. MUST BE A SLICE.
// fn: the predicate function.
// defaultValue: the default value.
// returns: the struct/value of the slice.
func FindOrDefault(source any, fn Predicate, defaultValue any) any {
// - source: the slice. MUST BE A SLICE.
// - fn: the predicate function.
// - defaultValue: the default value.
// - returns: the value of the slice.
//
// Example:
//
// // Output: "d"
// val := FindOrDefault([]string{"a", "b", "c"}, func(s string) bool {
// return s == "d"
// }, "d")
func FindOrDefault[T any](source []T, fn Predicate[T], defaultValue T) T {
item, err := Find(source, fn)
if err != nil {
if err.Error() == ErrElementNotFound {
return defaultValue
}
return defaultValue
}
return item
}
@@ -354,53 +286,53 @@ func FindOrDefault(source any, fn Predicate, defaultValue any) any {
// TakeWhile Produce the set of a slice according to a predicate function,
// Produce empty slice when predicate function not matched.
//
// data: the slice. MUST BE A SLICE.
// fn: the predicate function.
// returns: the set of the slice.
func TakeWhile(data any, fn Predicate) any {
aType := reflect.TypeOf(data)
if aType.Kind() != reflect.Slice {
panic("collections.TakeWhile: data must be a slice")
// - data: the slice. MUST BE A SLICE.
// - fn: the predicate function.
// - returns: the set of the slice.
//
// Example:
//
// // Output: []string{"a", "b"}
// sl := TakeWhile([]string{"a", "b", "c"}, func(s string) bool {
// return s != "c"
// })
func TakeWhile[T any](data []T, fn Predicate[T]) []T {
result := make([]T, 0)
if len(data) == 0 {
return result
}
sourceVal := reflect.ValueOf(data)
if sourceVal.Len() == 0 {
return MakeEmptySlice(aType.Elem())
}
result := reflect.New(reflect.SliceOf(aType.Elem())).Elem()
for i := 0; i < sourceVal.Len(); i++ {
s := sourceVal.Index(i).Interface()
if fn(s) {
result = reflect.Append(result, reflect.ValueOf(s))
for _, v := range data {
if fn(v) {
result = append(result, v)
}
}
return result.Interface()
return result
}
// ExceptWhile Produce the set of a slice except with a predicate function,
// Produce original slice when predicate function not match.
//
// data: the slice. MUST BE A SLICE.
// fn: the predicate function.
// returns: the set of the slice.
func ExceptWhile(data any, fn Predicate) any {
aType := reflect.TypeOf(data)
if aType.Kind() != reflect.Slice {
panic("collections.ExceptWhile: data must be a slice")
// - data: the slice. MUST BE A SLICE.
// - fn: the predicate function.
// - returns: the set of the slice.
//
// Example:
//
// // Output: []string{"a", "b"}
// sl := ExceptWhile([]string{"a", "b", "c"}, func(s string) bool {
// return s == "c"
// })
func ExceptWhile[T any](data []T, fn Predicate[T]) []T {
result := make([]T, 0)
if len(data) == 0 {
return result
}
sourceVal := reflect.ValueOf(data)
if sourceVal.Len() == 0 {
return MakeEmptySlice(aType.Elem())
}
result := reflect.New(reflect.SliceOf(aType.Elem())).Elem()
for i := 0; i < sourceVal.Len(); i++ {
s := sourceVal.Index(i).Interface()
if !fn(s) {
result = reflect.Append(result, reflect.ValueOf(s))
for _, v := range data {
if !fn(v) {
result = append(result, v)
}
}
return result.Interface()
return result
}
-22
View File
@@ -1,22 +0,0 @@
package arrutil
// type MapFn func(obj T) (target V, find bool)
// Map a list to new list
//
// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...]
func Map[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
flatArr := make([]V, 0, len(list))
for _, obj := range list {
if target, ok := mapFn(obj); ok {
flatArr = append(flatArr, target)
}
}
return flatArr
}
// Column alias of Map func
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
return Map(list, mapFn)
}
+52 -40
View File
@@ -29,6 +29,29 @@ func StringsJoin(sep string, ss ...string) string {
return strings.Join(ss, sep)
}
// JoinTyped join typed []T slice to string.
//
// Usage:
//
// JoinTyped(",", 1,2,3) // "1,2,3"
// JoinTyped(",", "a","b","c") // "a,b,c"
// JoinTyped[any](",", "a",1,"c") // "a,1,c"
func JoinTyped[T any](sep string, arr ...T) string {
if arr == nil {
return ""
}
var sb strings.Builder
for i, v := range arr {
if i > 0 {
sb.WriteString(sep)
}
sb.WriteString(strutil.QuietString(v))
}
return sb.String()
}
// JoinSlice join []any slice to string.
func JoinSlice(sep string, arr ...any) string {
if arr == nil {
@@ -47,9 +70,27 @@ func JoinSlice(sep string, arr ...any) string {
}
/*************************************************************
* helper func for slices
* convert func for ints
*************************************************************/
// 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()
}
// ToInt64s convert any(allow: array,slice) to []int64
func ToInt64s(arr any) (ret []int64, err error) {
rv := reflect.ValueOf(arr)
@@ -84,29 +125,9 @@ 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
}
/*************************************************************
* convert func for anys
*************************************************************/
// AnyToSlice convert any(allow: array,slice) to []any
func AnyToSlice(sl any) (ls []any, err error) {
@@ -136,15 +157,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)
@@ -168,16 +180,16 @@ func ToStrings(arr any) (ret []string, err error) {
return
}
// SliceToStrings convert []any to []string
// SliceToStrings safe convert []any to []string
func SliceToStrings(arr []any) []string {
return QuietStrings(arr)
}
// QuietStrings convert []any to []string
// QuietStrings safe convert []any to []string
func QuietStrings(arr []any) []string {
ss := make([]string, len(arr))
for i, v := range arr {
ss[i] = strutil.QuietString(v)
ss[i] = strutil.SafeString(v)
}
return ss
}
@@ -219,8 +231,8 @@ func AnyToString(arr any) string {
// SliceToString convert []any to string
func SliceToString(arr ...any) string { return ToString(arr) }
// ToString simple and quickly convert []any to string
func ToString(arr []any) string {
// ToString simple and quickly convert []T to string
func ToString[T any](arr []T) string {
// like fmt.Println([]any(nil))
if arr == nil {
return "[]"
@@ -233,14 +245,14 @@ func ToString(arr []any) string {
if i > 0 {
sb.WriteByte(',')
}
sb.WriteString(strutil.QuietString(v))
sb.WriteString(strutil.SafeString(v))
}
sb.WriteByte(']')
return sb.String()
}
// CombineToMap combine two slice to map[K]V.
// CombineToMap combine []K and []V slice to map[K]V.
//
// If keys length is greater than values, the extra keys will be ignored.
func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V {
-64
View File
@@ -1,64 +0,0 @@
package arrutil
import (
"strconv"
"strings"
)
// Ints type
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, ",")
}
// Has given element
func (is Ints) Has(i int) bool {
for _, iv := range is {
if i == iv {
return true
}
}
return false
}
// Strings type
type Strings []string
// String to string
func (ss Strings) String() string {
return strings.Join(ss, ",")
}
// Join to string
func (ss Strings) Join(sep string) string {
return strings.Join(ss, sep)
}
// Has given element
func (ss Strings) Has(sub string) bool {
return ss.Contains(sub)
}
// Contains given element
func (ss Strings) Contains(sub string) bool {
for _, s := range ss {
if s == sub {
return true
}
}
return false
}
// First element value.
func (ss Strings) First() string {
if len(ss) > 0 {
return ss[0]
}
return ""
}
+6 -8
View File
@@ -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,10 +23,14 @@ type ArrFormatter struct {
func NewFormatter(arr any) *ArrFormatter {
f := &ArrFormatter{}
f.Src = arr
return f
}
// FormatIndent array data to string.
func FormatIndent(arr any, indent string) string {
return NewFormatter(arr).WithIndent(indent).Format()
}
// WithFn for config self
func (f *ArrFormatter) WithFn(fn func(f *ArrFormatter)) *ArrFormatter {
fn(f)
@@ -47,7 +51,6 @@ func (f *ArrFormatter) FormatTo(w io.Writer) {
// Format to string
func (f *ArrFormatter) String() string {
f.Format()
return f.Format()
}
@@ -118,8 +121,3 @@ func (f *ArrFormatter) doFormat() {
}
writer.WriteByte(']')
}
// FormatIndent array data to string.
func FormatIndent(arr any, indent string) string {
return NewFormatter(arr).WithIndent(indent).Format()
}
+216
View File
@@ -0,0 +1,216 @@
package arrutil
import (
"sort"
"strings"
"github.com/gookit/goutil/comdef"
)
// Ints type
type Ints[T comdef.Integer] []T
// String to string
func (is Ints[T]) String() string {
return ToString(is)
}
// Has given element
func (is Ints[T]) Has(i T) bool {
for _, iv := range is {
if i == iv {
return true
}
}
return false
}
// First element value.
func (is Ints[T]) First(defVal ...T) T {
if len(is) > 0 {
return is[0]
}
if len(defVal) > 0 {
return defVal[0]
}
panic("empty integer slice")
}
// Last element value.
func (is Ints[T]) Last(defVal ...T) T {
if len(is) > 0 {
return is[len(is)-1]
}
if len(defVal) > 0 {
return defVal[0]
}
panic("empty integer slice")
}
// Sort the int slice
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
type Strings []string
// String to string
func (ss Strings) String() string {
return strings.Join(ss, ",")
}
// Join to string
func (ss Strings) Join(sep string) string {
return strings.Join(ss, sep)
}
// Has given element
func (ss Strings) Has(sub string) bool {
return ss.Contains(sub)
}
// Contains given element
func (ss Strings) Contains(sub string) bool {
for _, s := range ss {
if s == sub {
return true
}
}
return false
}
// First element value.
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(defVal ...string) string {
if len(ss) > 0 {
return ss[len(ss)-1]
}
if len(defVal) > 0 {
return defVal[0]
}
panic("empty string list")
}
// 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 SortedList[T]) IsEmpty() bool {
return len(ls) == 0
}
// String to string
func (ls SortedList[T]) String() string {
return ToString(ls)
}
// Has given element
func (ls SortedList[T]) Has(el T) bool {
return ls.Contains(el)
}
// Contains given element
func (ls SortedList[T]) Contains(el T) bool {
for _, v := range ls {
if v == el {
return true
}
}
return false
}
// First element value.
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 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 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 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 SortedList[T]) Map[V any](mapFn MapFn[T, V]) SortedList[V] {
// return Map(ls, mapFn)
// }
// Sort the slice
func (ls SortedList[T]) Sort() {
sort.Sort(ls)
}
+102
View File
@@ -0,0 +1,102 @@
package arrutil
import (
"reflect"
"github.com/gookit/goutil/comdef"
)
// Reverse any T slice.
//
// eg: []string{"site", "user", "info", "0"} -> []string{"0", "info", "user", "site"}
func Reverse[T any](ls []T) {
ln := len(ls)
for i := 0; i < ln/2; i++ {
li := ln - i - 1
ls[i], ls[li] = ls[li], ls[i]
}
}
// Remove give element from slice []T.
//
// eg: []string{"site", "user", "info", "0"} -> []string{"site", "user", "info"}
func Remove[T comdef.Compared](ls []T, val T) []T {
return Filter(ls, func(el T) bool {
return el != val
})
}
// Filter given slice, default will filter zero value.
//
// Usage:
//
// // output: [a, b]
// ss := arrutil.Filter([]string{"a", "", "b", ""})
func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T {
var fn comdef.MatchFunc[T]
if len(filter) > 0 && filter[0] != nil {
fn = filter[0]
} else {
fn = func(el T) bool {
return !reflect.ValueOf(el).IsZero()
}
}
newLs := make([]T, 0, len(ls))
for _, el := range ls {
if fn(el) {
newLs = append(newLs, el)
}
}
return newLs
}
// MapFn map handle function type.
type MapFn[T any, V any] func(input T) (target V, find bool)
// Map a list to new list
//
// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...]
func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V {
flatArr := make([]V, 0, len(list))
for _, obj := range list {
if target, ok := mapFn(obj); ok {
flatArr = append(flatArr, target)
}
}
return flatArr
}
// Column alias of Map func
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
return Map(list, mapFn)
}
// Unique value in the given slice data.
func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
if len(list) < 2 {
return list
}
valMap := make(map[T]struct{}, len(list))
uniArr := make([]T, 0, len(list))
for _, t := range list {
if _, ok := valMap[t]; !ok {
valMap[t] = struct{}{}
uniArr = append(uniArr, t)
}
}
return uniArr
}
// IndexOf value in given slice.
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
for i, v := range list {
if v == val {
return i
}
}
return -1
}
+137
View File
@@ -0,0 +1,137 @@
package arrutil
import (
"strconv"
"strings"
"github.com/gookit/goutil/comdef"
)
// StringsToAnys convert []string to []any
func StringsToAnys(ss []string) []any {
args := make([]any, len(ss))
for i, s := range ss {
args[i] = s
}
return args
}
// StringsToSlice convert []string to []any. alias of StringsToAnys()
func StringsToSlice(ss []string) []any {
return StringsToAnys(ss)
}
// 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
}
// StringsUnique unique string slice
func StringsUnique(ss []string) []string {
var unique []string
for _, s := range ss {
if !StringsContains(unique, s) {
unique = append(unique, s)
}
}
return unique
}
// StringsContains check string slice contains string
func StringsContains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
}
// StringsRemove value form a string slice
func StringsRemove(ss []string, s string) []string {
return StringsFilter(ss, func(el string) bool {
return s != el
})
}
// StringsFilter given strings, default will filter emtpy string.
//
// Usage:
//
// // output: [a, b]
// ss := arrutil.StringsFilter([]string{"a", "", "b", ""})
func StringsFilter(ss []string, filter ...comdef.StringMatchFunc) []string {
var fn comdef.StringMatchFunc
if len(filter) > 0 && filter[0] != nil {
fn = filter[0]
} else {
fn = func(s string) bool {
return s != ""
}
}
ns := make([]string, 0, len(ss))
for _, s := range ss {
if fn(s) {
ns = append(ns, s)
}
}
return ns
}
// StringsMap handle each string item, map to new strings
func StringsMap(ss []string, mapFn func(s string) string) []string {
ns := make([]string, 0, len(ss))
for _, s := range ss {
ns = append(ns, mapFn(s))
}
return ns
}
// TrimStrings trim string slice item.
//
// Usage:
//
// // output: [a, b, c]
// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.")
func TrimStrings(ss []string, cutSet ...string) []string {
cutSetLn := len(cutSet)
hasCutSet := cutSetLn > 0 && cutSet[0] != ""
var trimSet string
if hasCutSet {
trimSet = cutSet[0]
}
if cutSetLn > 1 {
trimSet = strings.Join(cutSet, "")
}
ns := make([]string, 0, len(ss))
for _, str := range ss {
if hasCutSet {
ns = append(ns, strings.Trim(str, trimSet))
} else {
ns = append(ns, strings.TrimSpace(str))
}
}
return ns
}