1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/util/slice/slice.go
2025-01-21 15:42:35 +01:00

258 lines
4.7 KiB
Go

package slice
import (
"hash/fnv"
"math/rand"
"sort"
"golang.org/x/exp/constraints"
"golang.org/x/exp/slices"
)
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(s []string, v string) int {
for i, sv := range s {
if sv == v {
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(s []string, pos int, v ...string) []string {
if len(s) <= pos {
return append(s, v...)
}
if pos == 0 {
return append(v, s[pos:]...)
}
return append(s[:pos], append(v, s[pos:]...)...)
}
// Remove reuses provided slice capacity. Provided s slice should not be used after without reassigning to the func return!
func Remove(s []string, v string) []string {
var n int
for _, x := range s {
if x != v {
s[n] = x
n++
}
}
return s[:n]
}
func Filter(vals []string, cond func(string) bool) []string {
var result = make([]string, 0, len(vals))
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(s1, s2 []string) bool {
if len(s1) != len(s2) {
return false
}
for i := range s1 {
if s1[i] != s2[i] {
return false
}
}
return true
}
func UnsortedEquals(s1, s2 []string) bool {
if len(s1) != len(s2) {
return false
}
s1Sorted := make([]string, len(s1))
s2Sorted := make([]string, len(s2))
copy(s1Sorted, s1)
copy(s2Sorted, s2)
sort.Strings(s1Sorted)
sort.Strings(s2Sorted)
return SortedEquals(s1Sorted, s2Sorted)
}
func ContainsSorted[T constraints.Ordered](seq []T, subseq []T) bool {
if len(seq) < len(subseq) {
return false
}
slices.Sort(seq)
slices.Sort(subseq)
i := 0
j := 0
for i < len(seq) && j < len(subseq) {
if seq[i] == subseq[j] {
i++
j++
} else if seq[i] < subseq[j] {
i++
} else {
// in this case we didn't find match for subseq[j] in seq
return false
}
}
// if we reached the end of subseq, then all elements were found
return j == len(subseq)
}
func DiscardDuplicatesSorted[T comparable](sorted []T) []T {
if len(sorted) <= 1 {
return sorted
}
cnt := 1
for i := 1; i < len(sorted); i++ {
if sorted[i] != sorted[i-1] {
sorted[cnt] = sorted[i]
cnt++
}
}
return sorted[:cnt]
}
func RemoveRepeatedSorted[T constraints.Ordered](nums []T) []T {
if len(nums) == 0 {
return nums
}
writeIndex := 0
i := 0
for i < len(nums) {
count := 1
for i+1 < len(nums) && nums[i] == nums[i+1] {
count++
i++
}
if count == 1 {
nums[writeIndex] = nums[i]
writeIndex++
}
i++
}
return nums[:writeIndex]
}
func RemoveUniqueElementsSorted[T constraints.Ordered](nums []T) []T {
if len(nums) == 0 {
return nums
}
writeIndex := 0
i := 0
for i < len(nums) {
count := 1
for i+1 < len(nums) && nums[i] == nums[i+1] {
count++
i++
}
if count > 1 {
for j := 0; j < count; j++ {
nums[writeIndex] = nums[i]
writeIndex++
}
}
i++
}
return nums[:writeIndex]
}
func DiscardDuplicatesSortedFunc[T any](sorted []T, equal func(T, T) bool) []T {
if len(sorted) <= 1 {
return sorted
}
cnt := 1
for i := 1; i < len(sorted); i++ {
if !equal(sorted[i], sorted[i-1]) {
sorted[cnt] = sorted[i]
cnt++
}
}
return sorted[:cnt]
}
func DiscardFromSlice[T any](elements []T, isDiscarded func(T) bool) []T {
var (
finishedIdx = 0
currentIdx = 0
)
for currentIdx < len(elements) {
if !isDiscarded(elements[currentIdx]) {
if finishedIdx != currentIdx {
elements[finishedIdx] = elements[currentIdx]
}
finishedIdx++
}
currentIdx++
}
elements = elements[:finishedIdx]
return elements
}
func CompareMaps[T comparable](map1, map2 map[T]struct{}) (both, first, second []T) {
both = []T{}
first = []T{}
second = []T{}
for key := range map1 {
if _, found := map2[key]; found {
both = append(both, key)
} else {
first = append(first, key)
}
}
for key := range map2 {
if _, found := map1[key]; !found {
second = append(second, key)
}
}
return both, first, second
}