github.com/kyleu/dbaudit@v0.0.2-0.20240321155047-ff2f2c940496/app/util/array.go (about) 1 // Package util - Content managed by Project Forge, see [projectforge.md] for details. 2 package util 3 4 import ( 5 "cmp" 6 "fmt" 7 "reflect" 8 "slices" 9 10 "github.com/pkg/errors" 11 "github.com/samber/lo" 12 ) 13 14 func StringArrayMaxLength(a []string) int { 15 return len(lo.MaxBy(a, func(x string, max string) bool { 16 return len(x) > len(max) 17 })) 18 } 19 20 func ArrayToStringArray[T any](a []T) []string { 21 return lo.Map(a, func(x T, _ int) string { 22 return fmt.Sprint(x) 23 }) 24 } 25 26 func StringArrayQuoted(a []string) []string { 27 return lo.Map(a, func(x string, _ int) string { 28 return fmt.Sprintf("%q", x) 29 }) 30 } 31 32 func StringArrayFromAny(a []any, maxLength int) []string { 33 ret := NewStringSlice(make([]string, 0, len(a))) 34 lo.ForEach(a, func(x any, _ int) { 35 var v string 36 switch t := x.(type) { 37 case string: 38 v = t 39 case []byte: 40 v = string(t) 41 default: 42 v = fmt.Sprint(x) 43 } 44 if maxLength > 0 && len(v) > maxLength { 45 v = v[:maxLength] + "... (truncated)" 46 } 47 ret.Push(v) 48 }) 49 return ret.Slice 50 } 51 52 func ArrayRemoveDuplicates[T comparable](x []T) []T { 53 return lo.Uniq(x) 54 } 55 56 func ArraySorted[T cmp.Ordered](x []T) []T { 57 slices.Sort(x) 58 return x 59 } 60 61 func StringArrayOxfordComma(names []string, separator string) string { 62 ret := "" 63 lo.ForEach(names, func(name string, idx int) { 64 if idx > 0 { 65 if idx == (len(names) - 1) { 66 if idx > 1 { 67 ret += "," 68 } 69 ret += " " + separator + " " 70 } else { 71 ret += ", " 72 } 73 } 74 ret += name 75 }) 76 return ret 77 } 78 79 func ArrayTransform[T any, U any](x []T, f func(T) U) []U { 80 return lo.Map(x, func(i T, _ int) U { 81 return f(i) 82 }) 83 } 84 85 func ArrayRemoveNil[T any](x []*T) []*T { 86 return lo.Reject(x, func(el *T, _ int) bool { 87 return el == nil 88 }) 89 } 90 91 func ArrayDereference[T any](x []*T) []T { 92 return lo.Map(x, func(el *T, _ int) T { 93 return lo.FromPtr(el) 94 }) 95 } 96 97 func LengthAny(dest any) int { 98 defer func() { _ = recover() }() 99 rfl := reflect.ValueOf(dest) 100 if rfl.Kind() == reflect.Ptr { 101 rfl = rfl.Elem() 102 } 103 return rfl.Len() 104 } 105 106 func ArrayFromAny(dest any) []any { 107 defer func() { _ = recover() }() 108 rfl := reflect.ValueOf(dest) 109 if rfl.Kind() == reflect.Ptr { 110 rfl = rfl.Elem() 111 } 112 if k := rfl.Kind(); k == reflect.Array || k == reflect.Slice { 113 return lo.Times(rfl.Len(), func(i int) any { 114 return rfl.Index(i).Interface() 115 }) 116 } 117 return []any{dest} 118 } 119 120 func ArrayFlatten[T any](arrs ...[]T) []T { 121 return lo.Flatten(arrs) 122 } 123 124 func ArrayFirstN[V any](items []V, n int) []V { 125 if n > len(items) { 126 return items 127 } 128 return items[:n] 129 } 130 131 func ArrayLastN[V any](items []V, n int) []V { 132 if n > len(items) { 133 return items 134 } 135 return items[len(items)-n:] 136 } 137 138 func MapError[T any, U any](xa []T, f func(el T, idx int) (U, error)) ([]U, error) { 139 ret := make([]U, 0, len(xa)) 140 for i, x := range xa { 141 candidate, err := f(x, i) 142 if err != nil { 143 return nil, errors.Wrapf(err, "error processing element [%d]", i) 144 } 145 ret = append(ret, candidate) 146 } 147 return ret, nil 148 }