2022-03-17 00:33:59 +00:00
|
|
|
package sliceutil
|
2021-10-28 03:25:17 +00:00
|
|
|
|
|
|
|
import "reflect"
|
|
|
|
|
2023-07-12 01:51:52 +00:00
|
|
|
// Exclude removes all instances of any value in toExclude from the vs
|
|
|
|
// slice. It returns the new or unchanged slice.
|
|
|
|
func Exclude[T comparable](vs []T, toExclude []T) []T {
|
|
|
|
var ret []T
|
|
|
|
for _, v := range vs {
|
|
|
|
if !Include(toExclude, v) {
|
|
|
|
ret = append(ret, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func Index[T comparable](vs []T, t T) int {
|
|
|
|
for i, v := range vs {
|
|
|
|
if v == t {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func Include[T comparable](vs []T, t T) bool {
|
|
|
|
return Index(vs, t) >= 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntAppendUnique appends toAdd to the vs int slice if toAdd does not already
|
|
|
|
// exist in the slice. It returns the new or unchanged int slice.
|
|
|
|
func AppendUnique[T comparable](vs []T, toAdd T) []T {
|
|
|
|
if Include(vs, toAdd) {
|
|
|
|
return vs
|
|
|
|
}
|
|
|
|
|
|
|
|
return append(vs, toAdd)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntAppendUniques appends a slice of values to the vs slice. It only
|
|
|
|
// appends values that do not already exist in the slice. It returns the new or
|
|
|
|
// unchanged slice.
|
|
|
|
func AppendUniques[T comparable](vs []T, toAdd []T) []T {
|
|
|
|
for _, v := range toAdd {
|
|
|
|
vs = AppendUnique(vs, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
return vs
|
|
|
|
}
|
|
|
|
|
2021-10-28 03:25:17 +00:00
|
|
|
// SliceSame returns true if the two provided lists have the same elements,
|
|
|
|
// regardless of order. Panics if either parameter is not a slice.
|
|
|
|
func SliceSame(a, b interface{}) bool {
|
|
|
|
v1 := reflect.ValueOf(a)
|
|
|
|
v2 := reflect.ValueOf(b)
|
|
|
|
|
|
|
|
if (v1.IsValid() && v1.Kind() != reflect.Slice) || (v2.IsValid() && v2.Kind() != reflect.Slice) {
|
|
|
|
panic("not a slice")
|
|
|
|
}
|
|
|
|
|
|
|
|
v1Len := 0
|
|
|
|
v2Len := 0
|
|
|
|
|
|
|
|
v1Valid := v1.IsValid()
|
|
|
|
v2Valid := v2.IsValid()
|
|
|
|
|
|
|
|
if v1Valid {
|
|
|
|
v1Len = v1.Len()
|
|
|
|
}
|
|
|
|
if v2Valid {
|
|
|
|
v2Len = v2.Len()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !v1Valid || !v2Valid {
|
|
|
|
return v1Len == v2Len
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1Len != v2Len {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1.Type() != v2.Type() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
visited := make(map[int]bool)
|
|
|
|
for i := 0; i < v1.Len(); i++ {
|
|
|
|
found := false
|
|
|
|
for j := 0; j < v2.Len(); j++ {
|
|
|
|
if visited[j] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if reflect.DeepEqual(v1.Index(i).Interface(), v2.Index(j).Interface()) {
|
|
|
|
found = true
|
|
|
|
visited[j] = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|