package langext import ( "errors" "fmt" "reflect" ) func BoolCount(arr ...bool) int { c := 0 for _, v := range arr { if v { c++ } } return c } func Range[T IntegerConstraint](start T, end T) []T { r := make([]T, 0, end-start) for i := start; i < end; i++ { r = append(r, i) } return r } func ForceArray[T any](v []T) []T { if v == nil { return make([]T, 0) } else { return v } } func ReverseArray[T any](v []T) { for i, j := 0, len(v)-1; i < j; i, j = i+1, j-1 { v[i], v[j] = v[j], v[i] } } func InArray[T comparable](needle T, haystack []T) bool { for _, v := range haystack { if v == needle { return true } } return false } func ArrUnique[T comparable](array []T) []T { m := make(map[T]bool, len(array)) for _, v := range array { m[v] = true } result := make([]T, 0, len(m)) for v := range m { result = append(result, v) } return result } func ArrUniqueStable[T comparable](array []T) []T { hist := make(map[T]bool, len(array)) result := make([]T, 0, len(array)) for _, v := range array { if _, ok := hist[v]; !ok { hist[v] = true result = append(result, v) } } return result } func ArrEqualsExact[T comparable](arr1 []T, arr2 []T) bool { if len(arr1) != len(arr2) { return false } for i := range arr1 { if arr1[i] != arr2[i] { return false } } return true } func ArrAll[T any](arr []T, fn func(T) bool) bool { for _, av := range arr { if !fn(av) { return false } } return true } func ArrAllErr[T any](arr []T, fn func(T) (bool, error)) (bool, error) { for _, av := range arr { v, err := fn(av) if err != nil { return false, err } if !v { return false, nil } } return true, nil } func ArrNone[T any](arr []T, fn func(T) bool) bool { for _, av := range arr { if fn(av) { return false } } return true } func ArrNoneErr[T any](arr []T, fn func(T) (bool, error)) (bool, error) { for _, av := range arr { v, err := fn(av) if err != nil { return false, err } if v { return false, nil } } return true, nil } func ArrAny[T any](arr []T, fn func(T) bool) bool { for _, av := range arr { if fn(av) { return true } } return false } func ArrAnyErr[T any](arr []T, fn func(T) (bool, error)) (bool, error) { for _, av := range arr { v, err := fn(av) if err != nil { return false, err } if v { return true, nil } } return false, nil } func ArrIdxAll(arr any, fn func(int) bool) bool { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { if !fn(i) { return false } } return true } func ArrIdxAllErr(arr any, fn func(int) (bool, error)) (bool, error) { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { v, err := fn(i) if err != nil { return false, err } if !v { return false, nil } } return true, nil } func ArrIdxNone(arr any, fn func(int) bool) bool { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { if fn(i) { return false } } return true } func ArrIdxNoneErr(arr any, fn func(int) (bool, error)) (bool, error) { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { v, err := fn(i) if err != nil { return false, err } if v { return false, nil } } return true, nil } func ArrIdxAny(arr any, fn func(int) bool) bool { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { if fn(i) { return true } } return false } func ArrIdxAnyErr(arr any, fn func(int) (bool, error)) (bool, error) { av := reflect.ValueOf(arr) for i := 0; i < av.Len(); i++ { v, err := fn(i) if err != nil { return false, err } if v { return true, nil } } return false, nil } func ArrFirst[T any](arr []T, comp func(v T) bool) (T, bool) { for _, v := range arr { if comp(v) { return v, true } } return *new(T), false } func ArrFirstOrNil[T any](arr []T, comp func(v T) bool) *T { for _, v := range arr { if comp(v) { return Ptr(v) } } return nil } func ArrLast[T any](arr []T, comp func(v T) bool) (T, bool) { found := false result := *new(T) for _, v := range arr { if comp(v) { found = true result = v } } return result, found } func ArrLastOrNil[T any](arr []T, comp func(v T) bool) *T { found := false result := *new(T) for _, v := range arr { if comp(v) { found = true result = v } } if found { return Ptr(result) } else { return nil } } func ArrFirstIndex[T comparable](arr []T, needle T) int { for i, v := range arr { if v == needle { return i } } return -1 } func ArrFirstIndexFunc[T any](arr []T, comp func(v T) bool) int { for i, v := range arr { if comp(v) { return i } } return -1 } func ArrLastIndex[T comparable](arr []T, needle T) int { result := -1 for i, v := range arr { if v == needle { result = i } } return result } func ArrLastIndexFunc[T any](arr []T, comp func(v T) bool) int { result := -1 for i, v := range arr { if comp(v) { result = i } } return result } func AddToSet[T comparable](set []T, add T) []T { for _, v := range set { if v == add { return set } } return append(set, add) } func ArrMap[T1 any, T2 any](arr []T1, conv func(v T1) T2) []T2 { r := make([]T2, len(arr)) for i, v := range arr { r[i] = conv(v) } return r } func ArrDeRef[T1 any](arr []*T1) []T1 { r := make([]T1, 0, len(arr)) for _, v := range arr { if v != nil { r = append(r, *v) } } return r } func MapMap[TK comparable, TV any, TR any](inmap map[TK]TV, conv func(k TK, v TV) TR) []TR { r := make([]TR, 0, len(inmap)) for k, v := range inmap { r = append(r, conv(k, v)) } return r } func MapMapErr[TK comparable, TV any, TR any](inmap map[TK]TV, conv func(k TK, v TV) (TR, error)) ([]TR, error) { r := make([]TR, 0, len(inmap)) for k, v := range inmap { elem, err := conv(k, v) if err != nil { return nil, err } r = append(r, elem) } return r, nil } func ArrMapExt[T1 any, T2 any](arr []T1, conv func(idx int, v T1) T2) []T2 { r := make([]T2, len(arr)) for i, v := range arr { r[i] = conv(i, v) } return r } func ArrMapErr[T1 any, T2 any](arr []T1, conv func(v T1) (T2, error)) ([]T2, error) { var err error r := make([]T2, len(arr)) for i, v := range arr { r[i], err = conv(v) if err != nil { return nil, err } } return r, nil } func ArrFilterMap[T1 any, T2 any](arr []T1, filter func(v T1) bool, conv func(v T1) T2) []T2 { r := make([]T2, 0, len(arr)) for _, v := range arr { if filter(v) { r = append(r, conv(v)) } } return r } func ArrFilter[T any](arr []T, filter func(v T) bool) []T { r := make([]T, 0, len(arr)) for _, v := range arr { if filter(v) { r = append(r, v) } } return r } func ArrSum[T NumberConstraint](arr []T) T { var r T = 0 for _, v := range arr { r += v } return r } func ArrFlatten[T1 any, T2 any](arr []T1, conv func(v T1) []T2) []T2 { r := make([]T2, 0, len(arr)) for _, v1 := range arr { r = append(r, conv(v1)...) } return r } func ArrFlattenDirect[T1 any](arr [][]T1) []T1 { r := make([]T1, 0, len(arr)) for _, v1 := range arr { r = append(r, v1...) } return r } func ArrCastToAny[T1 any](arr []T1) []any { r := make([]any, len(arr)) for i, v := range arr { r[i] = any(v) } return r } func ArrCastSafe[T1 any, T2 any](arr []T1) []T2 { r := make([]T2, 0, len(arr)) for _, v := range arr { if vcast, ok := any(v).(T2); ok { r = append(r, vcast) } } return r } func ArrCastErr[T1 any, T2 any](arr []T1) ([]T2, error) { r := make([]T2, len(arr)) for i, v := range arr { if vcast, ok := any(v).(T2); ok { r[i] = vcast } else { return nil, errors.New(fmt.Sprintf("Cannot cast element %d of type %T to type %v", i, v, *new(T2))) } } return r, nil } func ArrCastPanic[T1 any, T2 any](arr []T1) []T2 { r := make([]T2, len(arr)) for i, v := range arr { if vcast, ok := any(v).(T2); ok { r[i] = vcast } else { panic(fmt.Sprintf("Cannot cast element %d of type %T to type %v", i, v, *new(T2))) } } return r } func ArrConcat[T any](arr ...[]T) []T { c := 0 for _, v := range arr { c += len(v) } r := make([]T, c) i := 0 for _, av := range arr { for _, v := range av { r[i] = v i++ } } return r } // ArrAppend works similar to append(x, y, z) - but doe snot touch the old array and creates a new one func ArrAppend[T any](arr []T, add ...T) []T { r := ArrCopy(arr) for _, v := range add { r = append(r, v) } return r } // ArrPrepend works similar to append(x, y, z) - but doe snot touch the old array and creates a new one // Also - in contrast to ArrAppend - the add values are inserted at the start of the resulting array (in reverse order) func ArrPrepend[T any](arr []T, add ...T) []T { out := make([]T, len(arr)+len(add)) copy(out[len(add):], arr) for i := 0; i < len(add); i++ { out[len(add)-i-1] = add[i] } return out } // ArrCopy does a shallow copy of the 'in' array func ArrCopy[T any](in []T) []T { out := make([]T, len(in)) copy(out, in) return out } func ArrRemove[T comparable](arr []T, needle T) []T { idx := ArrFirstIndex(arr, needle) if idx >= 0 { return append(arr[:idx], arr[idx+1:]...) } return arr } func ArrRemoveAt[T any](arr []T, idx int) []T { return append(arr[:idx], arr[idx+1:]...) } func ArrExcept[T comparable](arr []T, needles ...T) []T { r := make([]T, 0, len(arr)) rmlist := ArrToSet(needles) for _, v := range arr { if _, ok := rmlist[v]; !ok { r = append(r, v) } } return r } func ArrayToInterface[T any](t []T) []interface{} { res := make([]interface{}, 0, len(t)) for i, _ := range t { res = append(res, t[i]) } return res } func JoinString(arr []string, delimiter string) string { str := "" for i, v := range arr { str += v if i < len(arr)-1 { str += delimiter } } return str } // ArrChunk splits the array into buckets of max-size `chunkSize` // order is being kept. // The last chunk may contain less than length elements. // // (chunkSize == -1) means no chunking // // see https://www.php.net/manual/en/function.array-chunk.php func ArrChunk[T any](arr []T, chunkSize int) [][]T { if chunkSize == -1 { return [][]T{arr} } res := make([][]T, 0, 1+len(arr)/chunkSize) i := 0 for i < len(arr) { right := i + chunkSize if right >= len(arr) { right = len(arr) } res = append(res, arr[i:right]) i = right } return res } func ArrGroupBy[T1 any, T2 comparable](arr []T1, groupfunc func(v T1) T2) map[T2][]T1 { r := make(map[T2][]T1) for _, v := range arr { key := groupfunc(v) if _, ok := r[key]; ok { r[key] = append(r[key], v) } else { r[key] = []T1{v} } } return r }