1// Package slice provides utility functions for working with slices in Go.
2package slice
3
4import (
5 "slices"
6)
7
8// GroupBy groups a slice of items by a key function.
9func GroupBy[T any, K comparable](list []T, key func(T) K) map[K][]T {
10 groups := make(map[K][]T)
11
12 for _, item := range list {
13 k := key(item)
14 groups[k] = append(groups[k], item)
15 }
16
17 return groups
18}
19
20// Take returns the first n elements of the given slice. If there are not
21// enough elements in the slice, the whole slice is returned.
22func Take[A any](slice []A, n int) []A {
23 if n > len(slice) {
24 return slice
25 }
26 return slice[:n]
27}
28
29// Last returns the last element of a slice and true. If the slice is empty, it
30// returns the zero value and false.
31func Last[T any](list []T) (T, bool) {
32 if len(list) == 0 {
33 var zero T
34 return zero, false
35 }
36 return list[len(list)-1], true
37}
38
39// Uniq returns a new slice with all duplicates removed.
40func Uniq[T comparable](list []T) []T {
41 seen := make(map[T]struct{}, len(list))
42 uniqList := make([]T, 0, len(list))
43
44 for _, item := range list {
45 if _, ok := seen[item]; !ok {
46 seen[item] = struct{}{}
47 uniqList = append(uniqList, item)
48 }
49 }
50
51 return uniqList
52}
53
54// Intersperse puts an item between each element of a slice, returning a new
55// slice.
56func Intersperse[T any](slice []T, insert T) []T {
57 if len(slice) <= 1 {
58 return slice
59 }
60
61 // Create a new slice with the required capacity.
62 result := make([]T, len(slice)*2-1)
63
64 for i := range slice {
65 // Fill the new slice with original elements and the insertion string.
66 result[i*2] = slice[i]
67
68 // Add the insertion string between items (except the last one).
69 if i < len(slice)-1 {
70 result[i*2+1] = insert
71 }
72 }
73
74 return result
75}
76
77// ContainsAny checks if any of the given values present in the list.
78func ContainsAny[T comparable](list []T, values ...T) bool {
79 return slices.ContainsFunc(list, func(v T) bool {
80 return slices.Contains(values, v)
81 })
82}
83
84// Shift removes and returns the first element of a slice.
85// It returns the removed element and the modified slice.
86// The third return value (ok) indicates whether an element was removed.
87func Shift[T any](slice []T) (element T, newSlice []T, ok bool) {
88 if len(slice) == 0 {
89 var zero T
90 return zero, slice, false
91 }
92 return slice[0], slice[1:], true
93}
94
95// Pop removes and returns the last element of a slice.
96// It returns the removed element and the modified slice.
97// The third return value (ok) indicates whether an element was removed.
98func Pop[T any](slice []T) (element T, newSlice []T, ok bool) {
99 if len(slice) == 0 {
100 var zero T
101 return zero, slice, false
102 }
103 lastIdx := len(slice) - 1
104 return slice[lastIdx], slice[:lastIdx], true
105}
106
107// DeleteAt removes and returns the element at the specified index.
108// It returns the removed element and the modified slice.
109// The third return value (ok) indicates whether an element was removed.
110func DeleteAt[T any](slice []T, index int) (element T, newSlice []T, ok bool) {
111 if index < 0 || index >= len(slice) {
112 var zero T
113 return zero, slice, false
114 }
115
116 element = slice[index]
117 newSlice = slices.Delete(slices.Clone(slice), index, index+1)
118
119 return element, newSlice, true
120}