2021-05-30 07:22:04 +02:00
|
|
|
package utils
|
|
|
|
|
2023-07-24 05:06:42 +02:00
|
|
|
import "golang.org/x/exp/slices"
|
|
|
|
|
2021-05-30 07:22:04 +02:00
|
|
|
// NextIndex returns the index of the element that comes after the given number
|
|
|
|
func NextIndex(numbers []int, currentNumber int) int {
|
|
|
|
for index, number := range numbers {
|
|
|
|
if number > currentNumber {
|
|
|
|
return index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return len(numbers) - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrevIndex returns the index that comes before the given number, cycling if we reach the end
|
|
|
|
func PrevIndex(numbers []int, currentNumber int) int {
|
|
|
|
end := len(numbers) - 1
|
|
|
|
for i := end; i >= 0; i-- {
|
|
|
|
if numbers[i] < currentNumber {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// NextIntInCycle returns the next int in a slice, returning to the first index if we've reached the end
|
|
|
|
func NextIntInCycle(sl []int, current int) int {
|
|
|
|
for i, val := range sl {
|
|
|
|
if val == current {
|
|
|
|
if i == len(sl)-1 {
|
|
|
|
return sl[0]
|
|
|
|
}
|
|
|
|
return sl[i+1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sl[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrevIntInCycle returns the prev int in a slice, returning to the first index if we've reached the end
|
|
|
|
func PrevIntInCycle(sl []int, current int) int {
|
|
|
|
for i, val := range sl {
|
|
|
|
if val == current {
|
|
|
|
if i > 0 {
|
|
|
|
return sl[i-1]
|
|
|
|
}
|
|
|
|
return sl[len(sl)-1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sl[len(sl)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
func StringArraysOverlap(strArrA []string, strArrB []string) bool {
|
|
|
|
for _, first := range strArrA {
|
|
|
|
for _, second := range strArrB {
|
|
|
|
if first == second {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2021-10-23 02:25:37 +02:00
|
|
|
|
|
|
|
func Limit(values []string, limit int) []string {
|
|
|
|
if len(values) > limit {
|
|
|
|
return values[:limit]
|
|
|
|
}
|
|
|
|
return values
|
|
|
|
}
|
|
|
|
|
2021-10-23 09:17:35 +02:00
|
|
|
func LimitStr(value string, limit int) string {
|
2021-10-23 13:46:37 +02:00
|
|
|
n := 0
|
|
|
|
for i := range value {
|
|
|
|
if n >= limit {
|
|
|
|
return value[:i]
|
|
|
|
}
|
|
|
|
n++
|
2021-10-23 09:17:35 +02:00
|
|
|
}
|
|
|
|
return value
|
|
|
|
}
|
2022-03-20 04:59:33 +02:00
|
|
|
|
|
|
|
// Similar to a regular GroupBy, except that each item can be grouped under multiple keys,
|
|
|
|
// so the callback returns a slice of keys instead of just one key.
|
|
|
|
func MuiltiGroupBy[T any, K comparable](slice []T, f func(T) []K) map[K][]T {
|
|
|
|
result := map[K][]T{}
|
|
|
|
for _, item := range slice {
|
|
|
|
for _, key := range f(item) {
|
|
|
|
if _, ok := result[key]; !ok {
|
|
|
|
result[key] = []T{item}
|
|
|
|
} else {
|
|
|
|
result[key] = append(result[key], item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
2023-04-04 10:23:50 +02:00
|
|
|
|
|
|
|
// Returns a new slice with the element at index 'from' moved to index 'to'.
|
|
|
|
// Does not mutate original slice.
|
|
|
|
func MoveElement[T any](slice []T, from int, to int) []T {
|
|
|
|
newSlice := make([]T, len(slice))
|
|
|
|
copy(newSlice, slice)
|
|
|
|
|
|
|
|
if from == to {
|
|
|
|
return newSlice
|
|
|
|
}
|
|
|
|
|
|
|
|
if from < to {
|
|
|
|
copy(newSlice[from:to+1], newSlice[from+1:to+1])
|
|
|
|
} else {
|
|
|
|
copy(newSlice[to+1:from+1], newSlice[to:from])
|
|
|
|
}
|
|
|
|
|
|
|
|
newSlice[to] = slice[from]
|
|
|
|
|
|
|
|
return newSlice
|
|
|
|
}
|
2023-05-27 06:14:43 +02:00
|
|
|
|
|
|
|
func ValuesAtIndices[T any](slice []T, indices []int) []T {
|
|
|
|
result := make([]T, len(indices))
|
|
|
|
for i, index := range indices {
|
|
|
|
// gracefully handling the situation where the index is out of bounds
|
|
|
|
if index < len(slice) {
|
|
|
|
result[i] = slice[index]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
2023-07-24 05:06:42 +02:00
|
|
|
|
|
|
|
// returns two slices: the first is for elements that pass the test, the second for those that don't.
|
|
|
|
func Partition[T any](slice []T, test func(T) bool) ([]T, []T) {
|
|
|
|
left := make([]T, 0, len(slice))
|
|
|
|
right := make([]T, 0, len(slice))
|
|
|
|
|
|
|
|
for _, value := range slice {
|
|
|
|
if test(value) {
|
|
|
|
left = append(left, value)
|
|
|
|
} else {
|
|
|
|
right = append(right, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return left, right
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepends items to the beginning of a slice.
|
|
|
|
// E.g. Prepend([]int{1,2}, 3, 4) = []int{3,4,1,2}
|
|
|
|
// Mutates original slice. Intended usage is to reassign the slice result to the input slice.
|
|
|
|
func Prepend[T any](slice []T, values ...T) []T {
|
|
|
|
return append(values, slice...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removes the element at the given index. Intended usage is to reassign the result to the input slice.
|
|
|
|
func Remove[T any](slice []T, index int) []T {
|
|
|
|
return slices.Delete(slice, index, index+1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removes the element at the 'fromIndex' and then inserts it at 'toIndex'.
|
|
|
|
// Operates on the input slice. Expected use is to reassign the result to the input slice.
|
|
|
|
func Move[T any](slice []T, fromIndex int, toIndex int) []T {
|
|
|
|
item := slice[fromIndex]
|
|
|
|
slice = Remove(slice, fromIndex)
|
|
|
|
return slices.Insert(slice, toIndex, item)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pops item from the end of the slice and returns it, along with the updated slice
|
|
|
|
// Mutates original slice. Intended usage is to reassign the slice result to the input slice.
|
|
|
|
func Pop[T any](slice []T) (T, []T) {
|
|
|
|
index := len(slice) - 1
|
|
|
|
value := slice[index]
|
|
|
|
slice = slice[0:index]
|
|
|
|
return value, slice
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shifts item from the beginning of the slice and returns it, along with the updated slice.
|
|
|
|
// Mutates original slice. Intended usage is to reassign the slice result to the input slice.
|
|
|
|
func Shift[T any](slice []T) (T, []T) {
|
|
|
|
value := slice[0]
|
|
|
|
slice = slice[1:]
|
|
|
|
return value, slice
|
|
|
|
}
|