|
|
@@ -11,10 +11,15 @@ import (
|
|
|
// ints, and other types not implementing []any can be worked with.
|
|
|
// For example, this is useful if you need to work on the output of regexs.
|
|
|
|
|
|
+// list creates a new list (slice) containing the provided arguments.
|
|
|
+// It accepts any number of arguments of any type and returns them as a slice.
|
|
|
func list(v ...any) []any {
|
|
|
return v
|
|
|
}
|
|
|
|
|
|
+// push appends an element to the end of a list (slice or array).
|
|
|
+// It takes a list and a value, and returns a new list with the value appended.
|
|
|
+// This function will panic if the first argument is not a slice or array.
|
|
|
func push(list any, v any) []any {
|
|
|
l, err := mustPush(list, v)
|
|
|
if err != nil {
|
|
|
@@ -23,99 +28,103 @@ func push(list any, v any) []any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustPush is the implementation of push that returns an error instead of panicking.
|
|
|
+// It converts the input list to a slice of any type, then appends the value.
|
|
|
func mustPush(list any, v any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
nl := make([]any, l)
|
|
|
for i := 0; i < l; i++ {
|
|
|
nl[i] = l2.Index(i).Interface()
|
|
|
}
|
|
|
-
|
|
|
return append(nl, v), nil
|
|
|
-
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot push on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// prepend adds an element to the beginning of a list (slice or array).
|
|
|
+// It takes a list and a value, and returns a new list with the value at the start.
|
|
|
+// This function will panic if the first argument is not a slice or array.
|
|
|
func prepend(list any, v any) []any {
|
|
|
l, err := mustPrepend(list, v)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustPrepend is the implementation of prepend that returns an error instead of panicking.
|
|
|
+// It converts the input list to a slice of any type, then prepends the value.
|
|
|
func mustPrepend(list any, v any) ([]any, error) {
|
|
|
- //return append([]any{v}, list...)
|
|
|
-
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
nl := make([]any, l)
|
|
|
for i := 0; i < l; i++ {
|
|
|
nl[i] = l2.Index(i).Interface()
|
|
|
}
|
|
|
-
|
|
|
return append([]any{v}, nl...), nil
|
|
|
-
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot prepend on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// chunk divides a list into sub-lists of the specified size.
|
|
|
+// It takes a size and a list, and returns a list of lists, each containing
|
|
|
+// up to 'size' elements from the original list.
|
|
|
+// This function will panic if the second argument is not a slice or array.
|
|
|
func chunk(size int, list any) [][]any {
|
|
|
l, err := mustChunk(size, list)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustChunk is the implementation of chunk that returns an error instead of panicking.
|
|
|
+// It divides the input list into chunks of the specified size.
|
|
|
func mustChunk(size int, list any) ([][]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
-
|
|
|
- cs := int(math.Floor(float64(l-1)/float64(size)) + 1)
|
|
|
- nl := make([][]any, cs)
|
|
|
-
|
|
|
- for i := 0; i < cs; i++ {
|
|
|
+ numChunks := int(math.Floor(float64(l-1)/float64(size)) + 1)
|
|
|
+ if numChunks > sliceSizeLimit {
|
|
|
+ return nil, fmt.Errorf("number of chunks %d exceeds maximum limit of %d", numChunks, sliceSizeLimit)
|
|
|
+ }
|
|
|
+ result := make([][]any, numChunks)
|
|
|
+ for i := 0; i < numChunks; i++ {
|
|
|
clen := size
|
|
|
- if i == cs-1 {
|
|
|
+ // Handle the last chunk which might be smaller
|
|
|
+ if i == numChunks-1 {
|
|
|
clen = int(math.Floor(math.Mod(float64(l), float64(size))))
|
|
|
if clen == 0 {
|
|
|
clen = size
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- nl[i] = make([]any, clen)
|
|
|
-
|
|
|
+ result[i] = make([]any, clen)
|
|
|
for j := 0; j < clen; j++ {
|
|
|
ix := i*size + j
|
|
|
- nl[i][j] = l2.Index(ix).Interface()
|
|
|
+ result[i][j] = l2.Index(ix).Interface()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return nl, nil
|
|
|
+ return result, nil
|
|
|
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot chunk type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// last returns the last element of a list (slice or array).
|
|
|
+// If the list is empty, it returns nil.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func last(list any) any {
|
|
|
l, err := mustLast(list)
|
|
|
if err != nil {
|
|
|
@@ -125,6 +134,8 @@ func last(list any) any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustLast is the implementation of last that returns an error instead of panicking.
|
|
|
+// It returns the last element of the list or nil if the list is empty.
|
|
|
func mustLast(list any) (any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
@@ -142,6 +153,9 @@ func mustLast(list any) (any, error) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// first returns the first element of a list (slice or array).
|
|
|
+// If the list is empty, it returns nil.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func first(list any) any {
|
|
|
l, err := mustFirst(list)
|
|
|
if err != nil {
|
|
|
@@ -151,6 +165,8 @@ func first(list any) any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustFirst is the implementation of first that returns an error instead of panicking.
|
|
|
+// It returns the first element of the list or nil if the list is empty.
|
|
|
func mustFirst(list any) (any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
@@ -168,6 +184,9 @@ func mustFirst(list any) (any, error) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// rest returns all elements of a list except the first one.
|
|
|
+// If the list is empty, it returns nil.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func rest(list any) []any {
|
|
|
l, err := mustRest(list)
|
|
|
if err != nil {
|
|
|
@@ -177,28 +196,30 @@ func rest(list any) []any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustRest is the implementation of rest that returns an error instead of panicking.
|
|
|
+// It returns all elements of the list except the first one, or nil if the list is empty.
|
|
|
func mustRest(list any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
if l == 0 {
|
|
|
return nil, nil
|
|
|
}
|
|
|
-
|
|
|
nl := make([]any, l-1)
|
|
|
for i := 1; i < l; i++ {
|
|
|
nl[i-1] = l2.Index(i).Interface()
|
|
|
}
|
|
|
-
|
|
|
return nl, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot find rest on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// initial returns all elements of a list except the last one.
|
|
|
+// If the list is empty, it returns nil.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func initial(list any) []any {
|
|
|
l, err := mustInitial(list)
|
|
|
if err != nil {
|
|
|
@@ -208,28 +229,30 @@ func initial(list any) []any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustInitial is the implementation of initial that returns an error instead of panicking.
|
|
|
+// It returns all elements of the list except the last one, or nil if the list is empty.
|
|
|
func mustInitial(list any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
if l == 0 {
|
|
|
return nil, nil
|
|
|
}
|
|
|
-
|
|
|
nl := make([]any, l-1)
|
|
|
for i := 0; i < l-1; i++ {
|
|
|
nl[i] = l2.Index(i).Interface()
|
|
|
}
|
|
|
-
|
|
|
return nl, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot find initial on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// sortAlpha sorts a list of strings alphabetically.
|
|
|
+// If the input is not a slice or array, it returns a single-element slice
|
|
|
+// containing the string representation of the input.
|
|
|
func sortAlpha(list any) []string {
|
|
|
k := reflect.Indirect(reflect.ValueOf(list)).Kind()
|
|
|
switch k {
|
|
|
@@ -242,6 +265,8 @@ func sortAlpha(list any) []string {
|
|
|
return []string{strval(list)}
|
|
|
}
|
|
|
|
|
|
+// reverse returns a new list with the elements in reverse order.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func reverse(v any) []any {
|
|
|
l, err := mustReverse(v)
|
|
|
if err != nil {
|
|
|
@@ -251,42 +276,45 @@ func reverse(v any) []any {
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustReverse is the implementation of reverse that returns an error instead of panicking.
|
|
|
+// It returns a new list with the elements in reverse order.
|
|
|
func mustReverse(v any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(v).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(v)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
// We do not sort in place because the incoming array should not be altered.
|
|
|
nl := make([]any, l)
|
|
|
for i := 0; i < l; i++ {
|
|
|
nl[l-i-1] = l2.Index(i).Interface()
|
|
|
}
|
|
|
-
|
|
|
return nl, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot find reverse on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// compact returns a new list with all "empty" elements removed.
|
|
|
+// An element is considered empty if it's nil, zero, an empty string, or an empty collection.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func compact(list any) []any {
|
|
|
l, err := mustCompact(list)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustCompact is the implementation of compact that returns an error instead of panicking.
|
|
|
+// It returns a new list with all "empty" elements removed.
|
|
|
func mustCompact(list any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
- nl := []any{}
|
|
|
+ var nl []any
|
|
|
var item any
|
|
|
for i := 0; i < l; i++ {
|
|
|
item = l2.Index(i).Interface()
|
|
|
@@ -294,30 +322,32 @@ func mustCompact(list any) ([]any, error) {
|
|
|
nl = append(nl, item)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return nl, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot compact on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// uniq returns a new list with duplicate elements removed.
|
|
|
+// The first occurrence of each element is kept.
|
|
|
+// This function will panic if the argument is not a slice or array.
|
|
|
func uniq(list any) []any {
|
|
|
l, err := mustUniq(list)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustUniq is the implementation of uniq that returns an error instead of panicking.
|
|
|
+// It returns a new list with duplicate elements removed.
|
|
|
func mustUniq(list any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
- dest := []any{}
|
|
|
+ var dest []any
|
|
|
var item any
|
|
|
for i := 0; i < l; i++ {
|
|
|
item = l2.Index(i).Interface()
|
|
|
@@ -325,13 +355,15 @@ func mustUniq(list any) ([]any, error) {
|
|
|
dest = append(dest, item)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return dest, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot find uniq on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// inList checks if a value is present in a list.
|
|
|
+// It uses deep equality comparison to check for matches.
|
|
|
+// Returns true if the value is found, false otherwise.
|
|
|
func inList(haystack []any, needle any) bool {
|
|
|
for _, h := range haystack {
|
|
|
if reflect.DeepEqual(needle, h) {
|
|
|
@@ -341,21 +373,23 @@ func inList(haystack []any, needle any) bool {
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
+// without returns a new list with all occurrences of the specified values removed.
|
|
|
+// This function will panic if the first argument is not a slice or array.
|
|
|
func without(list any, omit ...any) []any {
|
|
|
l, err := mustWithout(list, omit...)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustWithout is the implementation of without that returns an error instead of panicking.
|
|
|
+// It returns a new list with all occurrences of the specified values removed.
|
|
|
func mustWithout(list any, omit ...any) ([]any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
res := []any{}
|
|
|
var item any
|
|
|
@@ -365,22 +399,25 @@ func mustWithout(list any, omit ...any) ([]any, error) {
|
|
|
res = append(res, item)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return res, nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("cannot find without on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// has checks if a value is present in a list.
|
|
|
+// Returns true if the value is found, false otherwise.
|
|
|
+// This function will panic if the second argument is not a slice or array.
|
|
|
func has(needle any, haystack any) bool {
|
|
|
l, err := mustHas(needle, haystack)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustHas is the implementation of has that returns an error instead of panicking.
|
|
|
+// It checks if a value is present in a list.
|
|
|
func mustHas(needle any, haystack any) (bool, error) {
|
|
|
if haystack == nil {
|
|
|
return false, nil
|
|
|
@@ -397,38 +434,41 @@ func mustHas(needle any, haystack any) (bool, error) {
|
|
|
return true, nil
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return false, nil
|
|
|
default:
|
|
|
return false, fmt.Errorf("cannot find has on type %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// slice extracts a portion of a list based on the provided indices.
|
|
|
+// Usage examples:
|
|
|
// $list := [1, 2, 3, 4, 5]
|
|
|
// slice $list -> list[0:5] = list[:]
|
|
|
// slice $list 0 3 -> list[0:3] = list[:3]
|
|
|
// slice $list 3 5 -> list[3:5]
|
|
|
// slice $list 3 -> list[3:5] = list[3:]
|
|
|
+//
|
|
|
+// This function will panic if the first argument is not a slice or array.
|
|
|
func slice(list any, indices ...any) any {
|
|
|
l, err := mustSlice(list, indices...)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
}
|
|
|
-
|
|
|
return l
|
|
|
}
|
|
|
|
|
|
+// mustSlice is the implementation of slice that returns an error instead of panicking.
|
|
|
+// It extracts a portion of a list based on the provided indices.
|
|
|
func mustSlice(list any, indices ...any) (any, error) {
|
|
|
tp := reflect.TypeOf(list).Kind()
|
|
|
switch tp {
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
l2 := reflect.ValueOf(list)
|
|
|
-
|
|
|
l := l2.Len()
|
|
|
if l == 0 {
|
|
|
return nil, nil
|
|
|
}
|
|
|
-
|
|
|
+ // Determine start and end indices
|
|
|
var start, end int
|
|
|
if len(indices) > 0 {
|
|
|
start = toInt(indices[0])
|
|
|
@@ -438,13 +478,15 @@ func mustSlice(list any, indices ...any) (any, error) {
|
|
|
} else {
|
|
|
end = toInt(indices[1])
|
|
|
}
|
|
|
-
|
|
|
return l2.Slice(start, end).Interface(), nil
|
|
|
default:
|
|
|
return nil, fmt.Errorf("list should be type of slice or array but %s", tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// concat combines multiple lists into a single list.
|
|
|
+// It takes any number of lists and returns a new list containing all elements.
|
|
|
+// This function will panic if any argument is not a slice or array.
|
|
|
func concat(lists ...any) any {
|
|
|
var res []any
|
|
|
for _, list := range lists {
|