330 lines
7.4 KiB
Go
330 lines
7.4 KiB
Go
package slice
|
||
|
||
import (
|
||
"reflect"
|
||
)
|
||
|
||
// Slice 切片类型
|
||
type Slice[V any] []V
|
||
|
||
// GetValue 获取特定索引的元素,如果索引超出范围则返回零值
|
||
func GetValue[V any](slice []V, i int) (v V) {
|
||
if i >= 0 && i < len(slice) {
|
||
return slice[i]
|
||
}
|
||
return
|
||
}
|
||
|
||
// GetValueHandle 获取特定索引的元素,并通过 handle 进入传入,如果索引超出范围则不会进入 handle
|
||
func GetValueHandle[V any](slice []V, i int, handle func(v V)) {
|
||
if i >= 0 && i < len(slice) {
|
||
handle(slice[i])
|
||
}
|
||
}
|
||
|
||
// Del 删除特定索引的元素
|
||
func Del[V any](slice *[]V, index int) {
|
||
s := *slice
|
||
*slice = append(s[:index], s[index+1:]...)
|
||
}
|
||
|
||
// Copy 复制特定切片
|
||
func Copy[V any](slice []V) []V {
|
||
var s = make([]V, len(slice), len(slice))
|
||
for i := 0; i < len(slice); i++ {
|
||
s[i] = slice[i]
|
||
}
|
||
return s
|
||
}
|
||
|
||
// CopyMatrix 复制二维数组
|
||
func CopyMatrix[V any](slice [][]V) [][]V {
|
||
var s = make([][]V, len(slice), len(slice))
|
||
for i := 0; i < len(slice); i++ {
|
||
is := make([]V, len(slice[0]))
|
||
for j := 0; j < len(slice[0]); j++ {
|
||
is[j] = slice[i][j]
|
||
}
|
||
s[i] = is
|
||
}
|
||
return s
|
||
}
|
||
|
||
// Insert 在特定索引插入元素
|
||
func Insert[V any](slice *[]V, index int, value V) {
|
||
s := *slice
|
||
if index <= 0 {
|
||
*slice = append([]V{value}, s...)
|
||
} else if index >= len(s) {
|
||
*slice = append(s, value)
|
||
} else {
|
||
*slice = append(s[:index], append([]V{value}, s[index:]...)...)
|
||
}
|
||
}
|
||
|
||
// Move 移动特定索引
|
||
func Move[V any](slice *[]V, index, to int) {
|
||
s := *slice
|
||
v := s[index]
|
||
if index == to {
|
||
return
|
||
} else if to < index {
|
||
Del[V](slice, index)
|
||
Insert(slice, to, v)
|
||
} else {
|
||
Insert(slice, to, v)
|
||
Del[V](slice, index)
|
||
}
|
||
}
|
||
|
||
// NextLoop 返回 i 的下一个数组成员,当 i 达到数组长度时从 0 开始
|
||
// - 当 i 为 -1 时将返回第一个元素
|
||
func NextLoop[V any](slice []V, i int) (next int, value V) {
|
||
if i == -1 {
|
||
return 0, slice[0]
|
||
}
|
||
next = i + 1
|
||
if next == len(slice) {
|
||
next = 0
|
||
}
|
||
return next, slice[next]
|
||
}
|
||
|
||
// PrevLoop 返回 i 的上一个数组成员,当 i 为 0 时从数组末尾开始
|
||
// - 当 i 为 -1 时将返回最后一个元素
|
||
func PrevLoop[V any](slice []V, i int) (prev int, value V) {
|
||
if i == -1 {
|
||
return len(slice) - 1, slice[len(slice)-1]
|
||
}
|
||
prev = i - 1
|
||
if prev == -1 {
|
||
prev = len(slice) - 1
|
||
}
|
||
return prev, slice[prev]
|
||
}
|
||
|
||
// Reverse 反转数组
|
||
func Reverse[V any](slice []V) {
|
||
for i := 0; i < len(slice)/2; i++ {
|
||
slice[i], slice[len(slice)-1-i] = slice[len(slice)-1-i], slice[i]
|
||
}
|
||
}
|
||
|
||
// Distinct 去重
|
||
func Distinct[V any](slice []V) []V {
|
||
var result []V
|
||
for i := range slice {
|
||
flag := true
|
||
for j := range result {
|
||
if reflect.DeepEqual(slice[i], result[j]) {
|
||
flag = false
|
||
break
|
||
}
|
||
}
|
||
if flag {
|
||
result = append(result, slice[i])
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// Swap 交换数组中的两个元素
|
||
func Swap[V any](slice []V, i, j int) {
|
||
slice[i], slice[j] = slice[j], slice[i]
|
||
}
|
||
|
||
// ToMap 将数组转换为 map
|
||
func ToMap[K comparable, V any](slice []V, key func(V) K) map[K]V {
|
||
m := make(map[K]V)
|
||
for _, v := range slice {
|
||
m[key(v)] = v
|
||
}
|
||
return m
|
||
}
|
||
|
||
// ToSet 将数组转换为 set
|
||
func ToSet[V comparable](slice []V) map[V]struct{} {
|
||
m := make(map[V]struct{})
|
||
for _, v := range slice {
|
||
m[v] = struct{}{}
|
||
}
|
||
return m
|
||
}
|
||
|
||
// Merge 合并多个数组
|
||
func Merge[V any](slices ...[]V) []V {
|
||
var slice []V
|
||
for _, s := range slices {
|
||
slice = append(slice, s...)
|
||
}
|
||
return slice
|
||
}
|
||
|
||
// GetStartPart 获取数组的前 n 个元素
|
||
func GetStartPart[V any](slice []V, n int) []V {
|
||
if n > len(slice) {
|
||
n = len(slice)
|
||
}
|
||
return slice[:n]
|
||
}
|
||
|
||
// GetEndPart 获取数组的后 n 个元素
|
||
func GetEndPart[V any](slice []V, n int) []V {
|
||
if n > len(slice) {
|
||
n = len(slice)
|
||
}
|
||
return slice[len(slice)-n:]
|
||
}
|
||
|
||
// GetPart 获取指定区间的元素
|
||
func GetPart[V any](slice []V, start, end int) []V {
|
||
if start < 0 {
|
||
start = 0
|
||
}
|
||
if end > len(slice) {
|
||
end = len(slice)
|
||
}
|
||
return slice[start:end]
|
||
}
|
||
|
||
// Contains 判断数组是否包含某个元素
|
||
func Contains[V comparable](slice []V, value V) bool {
|
||
for _, v := range slice {
|
||
if v == value {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// ContainsAny 判断数组是否包含某个元素
|
||
func ContainsAny[V any](slice []V, values V) bool {
|
||
for _, v := range slice {
|
||
if reflect.DeepEqual(v, values) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// GetIndex 判断数组是否包含某个元素,如果包含则返回索引
|
||
func GetIndex[V comparable](slice []V, value V) int {
|
||
for i, v := range slice {
|
||
if v == value {
|
||
return i
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
|
||
// GetIndexAny 判断数组是否包含某个元素,如果包含则返回索引
|
||
func GetIndexAny[V any](slice []V, values V) int {
|
||
for i, v := range slice {
|
||
if reflect.DeepEqual(v, values) {
|
||
return i
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
|
||
// Combinations 获取给定数组的所有组合,包括重复元素的组合
|
||
func Combinations[T any](a []T) [][]T {
|
||
var result [][]T
|
||
n := len(a)
|
||
for i := 0; i < (1 << n); i++ {
|
||
var currentCombination []T
|
||
for j := 0; j < n; j++ {
|
||
if (i & (1 << j)) != 0 {
|
||
currentCombination = append(currentCombination, a[j])
|
||
}
|
||
}
|
||
result = append(result, currentCombination)
|
||
}
|
||
return result
|
||
}
|
||
|
||
// CombinationsPari 从给定的两个数组中按照特定数量得到所有组合后,再将两个数组的组合进行组合
|
||
// - 例如从数组 A 中得到所有数量为2的组合,从数组 B 中得到所有数量为3的组合,再将两个组合进行组合,得到所有数量为5的组合
|
||
func CombinationsPari[T any](a, b []T, aCount, bCount int) [][]T {
|
||
var combinations [][]T
|
||
var as, bs = LimitedCombinations(a, aCount, aCount), LimitedCombinations(b, bCount, bCount)
|
||
for _, asi := range as {
|
||
for _, bsi := range bs {
|
||
combinations = append(combinations, append(asi, bsi...))
|
||
}
|
||
}
|
||
return combinations
|
||
}
|
||
|
||
// LimitedCombinations 获取给定数组的所有组合,且每个组合的成员数量限制在指定范围内
|
||
func LimitedCombinations[T any](a []T, minSize, maxSize int) [][]T {
|
||
n := len(a)
|
||
if n == 0 || minSize <= 0 || maxSize <= 0 || minSize > maxSize {
|
||
return nil
|
||
}
|
||
|
||
var result [][]T
|
||
var currentCombination []T
|
||
|
||
var backtrack func(startIndex int, currentSize int)
|
||
backtrack = func(startIndex int, currentSize int) {
|
||
if currentSize >= minSize && currentSize <= maxSize {
|
||
combination := make([]T, len(currentCombination))
|
||
copy(combination, currentCombination)
|
||
result = append(result, combination)
|
||
}
|
||
|
||
for i := startIndex; i < n; i++ {
|
||
currentCombination = append(currentCombination, a[i])
|
||
backtrack(i+1, currentSize+1)
|
||
currentCombination = currentCombination[:len(currentCombination)-1]
|
||
}
|
||
}
|
||
|
||
backtrack(0, 0)
|
||
return result
|
||
}
|
||
|
||
// IsIntersectWithCheck 判断两个切片是否有交集
|
||
func IsIntersectWithCheck[T any](a, b []T, checkHandle func(a, b T) bool) bool {
|
||
for _, a := range a {
|
||
for _, b := range b {
|
||
if checkHandle(a, b) {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// IsIntersect 判断两个切片是否有交集
|
||
func IsIntersect[T any](a, b []T) bool {
|
||
for _, a := range a {
|
||
for _, b := range b {
|
||
if reflect.DeepEqual(a, b) {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// SubWithCheck 获取移除指定元素后的切片
|
||
// - checkHandle 返回 true 表示需要移除
|
||
func SubWithCheck[T any](a, b []T, checkHandle func(a, b T) bool) []T {
|
||
var result []T
|
||
for _, a := range a {
|
||
flag := false
|
||
for _, b := range b {
|
||
if checkHandle(a, b) {
|
||
flag = true
|
||
break
|
||
}
|
||
}
|
||
if !flag {
|
||
result = append(result, a)
|
||
}
|
||
}
|
||
return result
|
||
}
|