slice.go

  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}