mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-08 05:47:07 +09:00
309 lines
5.5 KiB
Go
309 lines
5.5 KiB
Go
package slice
|
|
|
|
import (
|
|
"hash/fnv"
|
|
"math/rand"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/samber/lo"
|
|
"golang.org/x/exp/constraints"
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
func Union(a, b []string) []string {
|
|
set := make(map[string]struct{}, len(a))
|
|
for _, v := range a {
|
|
set[v] = struct{}{}
|
|
}
|
|
for _, v := range b {
|
|
if _, ok := set[v]; !ok {
|
|
a = append(a, v)
|
|
}
|
|
}
|
|
return a
|
|
}
|
|
|
|
func DifferenceRemovedAdded(a, b []string) (removed []string, added []string) {
|
|
var amap = map[string]struct{}{}
|
|
var bmap = map[string]struct{}{}
|
|
|
|
for _, item := range a {
|
|
amap[item] = struct{}{}
|
|
}
|
|
|
|
for _, item := range b {
|
|
if _, exists := amap[item]; !exists {
|
|
added = append(added, item)
|
|
}
|
|
bmap[item] = struct{}{}
|
|
}
|
|
|
|
for _, item := range a {
|
|
if _, exists := bmap[item]; !exists {
|
|
removed = append(removed, item)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func FindPos[T comparable](s []T, v T) int {
|
|
for i, sv := range s {
|
|
if sv == v {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func Find[T comparable](s []T, cond func(T) bool) int {
|
|
for i, sv := range s {
|
|
if cond(sv) {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// Difference returns the elements in `a` that aren't in `b`.
|
|
func Difference(a, b []string) []string {
|
|
var diff = make([]string, 0, len(a))
|
|
for _, a1 := range a {
|
|
if FindPos(b, a1) == -1 {
|
|
diff = append(diff, a1)
|
|
}
|
|
}
|
|
return diff
|
|
}
|
|
|
|
func Insert[T any](s []T, pos int, v ...T) []T {
|
|
if len(s) <= pos {
|
|
return append(s, v...)
|
|
}
|
|
if pos == 0 {
|
|
return append(v, s[pos:]...)
|
|
}
|
|
return append(s[:pos], append(v, s[pos:]...)...)
|
|
}
|
|
|
|
// RemoveMut reuses provided slice capacity. Provided s slice should not be used after without reassigning to the func return!
|
|
func RemoveMut[T comparable](s []T, v T) []T {
|
|
var n int
|
|
for _, x := range s {
|
|
if x != v {
|
|
s[n] = x
|
|
n++
|
|
}
|
|
}
|
|
return s[:n]
|
|
}
|
|
|
|
// Remove is an immutable analog of RemoveMut function. Input slice is copied and then modified
|
|
func Remove[T comparable](s []T, v T) []T {
|
|
var n int
|
|
sc := slices.Clone(s)
|
|
for _, x := range s {
|
|
if x != v {
|
|
sc[n] = x
|
|
n++
|
|
}
|
|
}
|
|
return sc[:n]
|
|
}
|
|
|
|
// RemoveIndex reuses provided slice capacity. Provided s slice should not be used after without reassigning to the func return!
|
|
func RemoveIndex[T any](s []T, idx int) []T {
|
|
var n int
|
|
for i, x := range s {
|
|
if i != idx {
|
|
s[n] = x
|
|
n++
|
|
}
|
|
}
|
|
return s[:n]
|
|
}
|
|
|
|
// RemoveN is an analog of Remove function, but removing a range of values
|
|
func RemoveN[T comparable](s []T, vs ...T) []T {
|
|
var (
|
|
n int
|
|
found bool
|
|
sc = slices.Clone(s)
|
|
)
|
|
if len(vs) == 0 {
|
|
return sc
|
|
}
|
|
for _, x := range s {
|
|
found = false
|
|
for _, v := range vs {
|
|
if x == v {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
sc[n] = x
|
|
n++
|
|
}
|
|
}
|
|
return sc[:n]
|
|
}
|
|
|
|
func Filter[T any](vals []T, cond func(T) bool) []T {
|
|
var result = make([]T, 0, len(vals))
|
|
for i := range vals {
|
|
if cond(vals[i]) {
|
|
result = append(result, vals[i])
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func FilterMut[T any](vals []T, cond func(T) bool) []T {
|
|
result := vals[:0]
|
|
for i := range vals {
|
|
if cond(vals[i]) {
|
|
result = append(result, vals[i])
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func GetRandomString(s []string, seed string) string {
|
|
rand.Seed(int64(hash(seed)))
|
|
return s[rand.Intn(len(s))]
|
|
}
|
|
|
|
func hash(s string) uint64 {
|
|
h := fnv.New64a()
|
|
h.Write([]byte(s))
|
|
return h.Sum64()
|
|
}
|
|
|
|
func SortedEquals[K constraints.Ordered](s1, s2 []K) bool {
|
|
if len(s1) != len(s2) {
|
|
return false
|
|
}
|
|
for i := range s1 {
|
|
if s1[i] != s2[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func UnsortedEqual[K constraints.Ordered](s1, s2 []K) bool {
|
|
if len(s1) != len(s2) {
|
|
return false
|
|
}
|
|
|
|
s1Sorted := make([]K, len(s1))
|
|
s2Sorted := make([]K, len(s2))
|
|
copy(s1Sorted, s1)
|
|
copy(s2Sorted, s2)
|
|
slices.Sort(s1Sorted)
|
|
slices.Sort(s2Sorted)
|
|
|
|
return SortedEquals(s1Sorted, s2Sorted)
|
|
}
|
|
|
|
func HasPrefix(value, prefix []string) bool {
|
|
if len(value) < len(prefix) {
|
|
return false
|
|
}
|
|
for i, p := range prefix {
|
|
if value[i] != p {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func Copy[T any](list []T) []T {
|
|
newList := make([]T, len(list))
|
|
copy(newList, list)
|
|
return newList
|
|
}
|
|
|
|
func Intersection(a, b []string) (res []string) {
|
|
sort.Strings(a)
|
|
sort.Strings(b)
|
|
aIdx := 0
|
|
bIdx := 0
|
|
for aIdx < len(a) && bIdx < len(b) {
|
|
cmp := strings.Compare(a[aIdx], b[bIdx])
|
|
switch cmp {
|
|
case 0:
|
|
res = append(res, a[aIdx])
|
|
aIdx++
|
|
bIdx++
|
|
case -1:
|
|
aIdx++
|
|
case 1:
|
|
bIdx++
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func ReplaceFirstBy[T comparable](s []T, el T, pred func(el T) bool) []T {
|
|
for i, el2 := range s {
|
|
if pred(el2) {
|
|
s[i] = el
|
|
break
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func FilterCID(cids []string) []string {
|
|
return lo.Filter(cids, func(item string, index int) bool {
|
|
_, err := cid.Parse(item)
|
|
return err == nil
|
|
})
|
|
}
|
|
|
|
func StringsInto[T ~string](from []string) []T {
|
|
to := make([]T, len(from))
|
|
for i, v := range from {
|
|
to[i] = T(v)
|
|
}
|
|
return to
|
|
}
|
|
|
|
func IntoStrings[T ~string](from []T) []string {
|
|
to := make([]string, len(from))
|
|
for i, v := range from {
|
|
to[i] = string(v)
|
|
}
|
|
return to
|
|
}
|
|
|
|
type numeric interface {
|
|
constraints.Integer | constraints.Float
|
|
}
|
|
|
|
func FloatsInto[T numeric](from []float64) []T {
|
|
to := make([]T, len(from))
|
|
for i, v := range from {
|
|
to[i] = T(v)
|
|
}
|
|
return to
|
|
}
|
|
|
|
// MergeUniqBy merges two slices with comparator. Resulting slice saves values' order and uniqueness.
|
|
// Input slices MUST contain only unique values
|
|
func MergeUniqBy[T comparable](s1, s2 []T, equal func(v1, v2 T) bool) (result []T) {
|
|
result = make([]T, len(s1))
|
|
copy(result, s1)
|
|
for _, v2 := range s2 {
|
|
if !slices.ContainsFunc(s1, func(v1 T) bool {
|
|
return equal(v1, v2)
|
|
}) {
|
|
result = append(result, v2)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|