prysm-pulse/shared/sliceutil/slice.go
Victor Farazdagi b577869ed6
Fixes import aliases (#8497)
* Fixes import aliases

* another fix

* reset gw files

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2021-02-22 23:20:57 +00:00

366 lines
8.2 KiB
Go

package sliceutil
import (
"strings"
types "github.com/prysmaticlabs/eth2-types"
)
// SubsetUint64 returns true if the first array is
// completely contained in the second array with time
// complexity of approximately o(n).
func SubsetUint64(a, b []uint64) bool {
if len(a) > len(b) {
return false
}
set := make(map[uint64]uint64, len(b))
for _, v := range b {
set[v]++
}
for _, v := range a {
if count, found := set[v]; !found {
return false
} else if count < 1 {
return false
} else {
set[v] = count - 1
}
}
return true
}
// IntersectionUint64 of any number of uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func IntersectionUint64(s ...[]uint64) []uint64 {
if len(s) == 0 {
return []uint64{}
}
if len(s) == 1 {
return s[0]
}
intersect := make([]uint64, 0)
m := make(map[uint64]int)
for _, k := range s[0] {
m[k] = 1
}
for i, num := 1, len(s); i < num; i++ {
for _, k := range s[i] {
// Increment and check only if item is present in both, and no increment has happened yet.
if _, found := m[k]; found && i == m[k] {
m[k]++
if m[k] == num {
intersect = append(intersect, k)
}
}
}
}
return intersect
}
// UnionUint64 of any number of uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func UnionUint64(s ...[]uint64) []uint64 {
if len(s) == 0 {
return []uint64{}
}
if len(s) == 1 {
return s[0]
}
set := s[0]
m := make(map[uint64]bool)
for i := 1; i < len(s); i++ {
a := s[i-1]
b := s[i]
for j := 0; j < len(a); j++ {
m[a[j]] = true
}
for j := 0; j < len(b); j++ {
if _, found := m[b[j]]; !found {
set = append(set, b[j])
}
}
}
return set
}
// SetUint64 returns a slice with only unique
// values from the provided list of indices.
func SetUint64(a []uint64) []uint64 {
// Remove duplicates indices.
intMap := map[uint64]bool{}
cleanedIndices := make([]uint64, 0, len(a))
for _, idx := range a {
if intMap[idx] {
continue
}
intMap[idx] = true
cleanedIndices = append(cleanedIndices, idx)
}
return cleanedIndices
}
// IsUint64Sorted verifies if a uint64 slice is sorted in ascending order.
func IsUint64Sorted(a []uint64) bool {
if len(a) == 0 || len(a) == 1 {
return true
}
for i := 1; i < len(a); i++ {
if a[i-1] > a[i] {
return false
}
}
return true
}
// NotUint64 returns the uint64 in slice b that are
// not in slice a with time complexity of approximately
// O(n) leveraging a map to check for element existence
// off by a constant factor of underlying map efficiency.
func NotUint64(a, b []uint64) []uint64 {
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// IsInUint64 returns true if a is in b and False otherwise.
func IsInUint64(a uint64, b []uint64) bool {
for _, v := range b {
if a == v {
return true
}
}
return false
}
// IntersectionInt64 of any number of int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func IntersectionInt64(s ...[]int64) []int64 {
if len(s) == 0 {
return []int64{}
}
if len(s) == 1 {
return s[0]
}
intersect := make([]int64, 0)
m := make(map[int64]int)
for _, k := range s[0] {
m[k] = 1
}
for i, num := 1, len(s); i < num; i++ {
for _, k := range s[i] {
if _, found := m[k]; found && i == m[k] {
m[k]++
if m[k] == num {
intersect = append(intersect, k)
}
}
}
}
return intersect
}
// UnionInt64 of any number of int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func UnionInt64(s ...[]int64) []int64 {
if len(s) == 0 {
return []int64{}
}
if len(s) == 1 {
return s[0]
}
set := s[0]
m := make(map[int64]bool)
for i := 1; i < len(s); i++ {
a := s[i-1]
b := s[i]
for j := 0; j < len(a); j++ {
m[a[j]] = true
}
for j := 0; j < len(b); j++ {
if _, found := m[b[j]]; !found {
set = append(set, b[j])
}
}
}
return set
}
// NotInt64 returns the int64 in slice a that are
// not in slice b with time complexity of approximately
// O(n) leveraging a map to check for element existence
// off by a constant factor of underlying map efficiency.
func NotInt64(a, b []int64) []int64 {
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// IsInInt64 returns true if a is in b and False otherwise.
func IsInInt64(a int64, b []int64) bool {
for _, v := range b {
if a == v {
return true
}
}
return false
}
// UnionByteSlices returns the all elements between sets of byte slices.
func UnionByteSlices(s ...[][]byte) [][]byte {
if len(s) == 0 {
return [][]byte{}
}
if len(s) == 1 {
return s[0]
}
set := s[0]
m := make(map[string]bool)
for i := 1; i < len(s); i++ {
for j := 0; j < len(s[i-1]); j++ {
m[string(s[i-1][j])] = true
}
for j := 0; j < len(s[i]); j++ {
if _, found := m[string(s[i][j])]; !found {
set = append(set, s[i][j])
}
}
}
return set
}
// IntersectionByteSlices returns the common elements between sets of byte slices.
func IntersectionByteSlices(s ...[][]byte) [][]byte {
if len(s) == 0 {
return [][]byte{}
}
if len(s) == 1 {
return s[0]
}
inter := make([][]byte, 0)
m := make(map[string]int)
for _, k := range s[0] {
m[string(k)] = 1
}
for i, num := 1, len(s); i < num; i++ {
for _, k := range s[i] {
if _, found := m[string(k)]; found && i == m[string(k)] {
m[string(k)]++
if m[string(k)] == num {
inter = append(inter, k)
}
}
}
}
return inter
}
// SplitCommaSeparated values from the list. Example: []string{"a,b", "c,d"} becomes []string{"a", "b", "c", "d"}.
func SplitCommaSeparated(arr []string) []string {
var result []string
for _, val := range arr {
result = append(result, strings.Split(val, ",")...)
}
return result
}
// SplitOffset returns the start index of a given list splits into chunks,
// it computes (listsize * index) / chunks.
//
// Spec pseudocode definition:
// def get_split_offset(list_size: int, chunks: int, index: int) -> int:
// """
// Returns a value such that for a list L, chunk count k and index i,
// split(L, k)[i] == L[get_split_offset(len(L), k, i): get_split_offset(len(L), k, i+1)]
// """
// return (list_size * index) // chunks
func SplitOffset(listSize, chunks, index uint64) uint64 {
return (listSize * index) / chunks
}
// IntersectionSlot of any number of types.Slot slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func IntersectionSlot(s ...[]types.Slot) []types.Slot {
if len(s) == 0 {
return []types.Slot{}
}
if len(s) == 1 {
return s[0]
}
intersect := make([]types.Slot, 0)
m := make(map[types.Slot]int)
for _, k := range s[0] {
m[k] = 1
}
for i, num := 1, len(s); i < num; i++ {
for _, k := range s[i] {
// Increment and check only if item is present in both, and no increment has happened yet.
if _, found := m[k]; found && i == m[k] {
m[k]++
if m[k] == num {
intersect = append(intersect, k)
}
}
}
}
return intersect
}
// NotSlot returns the types.Slot in slice b that are
// not in slice a with time complexity of approximately
// O(n) leveraging a map to check for element existence
// off by a constant factor of underlying map efficiency.
func NotSlot(a, b []types.Slot) []types.Slot {
set := make([]types.Slot, 0)
m := make(map[types.Slot]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// IsInSlots returns true if a is in b and False otherwise.
func IsInSlots(a types.Slot, b []types.Slot) bool {
for _, v := range b {
if a == v {
return true
}
}
return false
}