github.com/prysmaticlabs/prysm@v1.4.4/shared/sliceutil/slice.go (about)

     1  package sliceutil
     2  
     3  import (
     4  	"strings"
     5  
     6  	types "github.com/prysmaticlabs/eth2-types"
     7  )
     8  
     9  // SubsetUint64 returns true if the first array is
    10  // completely contained in the second array with time
    11  // complexity of approximately o(n).
    12  func SubsetUint64(a, b []uint64) bool {
    13  	if len(a) > len(b) {
    14  		return false
    15  	}
    16  
    17  	set := make(map[uint64]uint64, len(b))
    18  	for _, v := range b {
    19  		set[v]++
    20  	}
    21  
    22  	for _, v := range a {
    23  		if count, found := set[v]; !found {
    24  			return false
    25  		} else if count < 1 {
    26  			return false
    27  		} else {
    28  			set[v] = count - 1
    29  		}
    30  	}
    31  	return true
    32  }
    33  
    34  // IntersectionUint64 of any number of uint64 slices with time
    35  // complexity of approximately O(n) leveraging a map to
    36  // check for element existence off by a constant factor
    37  // of underlying map efficiency.
    38  func IntersectionUint64(s ...[]uint64) []uint64 {
    39  	if len(s) == 0 {
    40  		return []uint64{}
    41  	}
    42  	if len(s) == 1 {
    43  		return s[0]
    44  	}
    45  	intersect := make([]uint64, 0)
    46  	m := make(map[uint64]int)
    47  	for _, k := range s[0] {
    48  		m[k] = 1
    49  	}
    50  	for i, num := 1, len(s); i < num; i++ {
    51  		for _, k := range s[i] {
    52  			// Increment and check only if item is present in both, and no increment has happened yet.
    53  			if _, found := m[k]; found && i == m[k] {
    54  				m[k]++
    55  				if m[k] == num {
    56  					intersect = append(intersect, k)
    57  				}
    58  			}
    59  		}
    60  	}
    61  	return intersect
    62  }
    63  
    64  // UnionUint64 of any number of uint64 slices with time
    65  // complexity of approximately O(n) leveraging a map to
    66  // check for element existence off by a constant factor
    67  // of underlying map efficiency.
    68  func UnionUint64(s ...[]uint64) []uint64 {
    69  	if len(s) == 0 {
    70  		return []uint64{}
    71  	}
    72  	if len(s) == 1 {
    73  		return s[0]
    74  	}
    75  	set := s[0]
    76  	m := make(map[uint64]bool)
    77  	for i := 1; i < len(s); i++ {
    78  		a := s[i-1]
    79  		b := s[i]
    80  		for j := 0; j < len(a); j++ {
    81  			m[a[j]] = true
    82  		}
    83  		for j := 0; j < len(b); j++ {
    84  			if _, found := m[b[j]]; !found {
    85  				set = append(set, b[j])
    86  			}
    87  		}
    88  	}
    89  	return set
    90  }
    91  
    92  // SetUint64 returns a slice with only unique
    93  // values from the provided list of indices.
    94  func SetUint64(a []uint64) []uint64 {
    95  	// Remove duplicates indices.
    96  	intMap := map[uint64]bool{}
    97  	cleanedIndices := make([]uint64, 0, len(a))
    98  	for _, idx := range a {
    99  		if intMap[idx] {
   100  			continue
   101  		}
   102  		intMap[idx] = true
   103  		cleanedIndices = append(cleanedIndices, idx)
   104  	}
   105  	return cleanedIndices
   106  }
   107  
   108  // IsUint64Sorted verifies if a uint64 slice is sorted in ascending order.
   109  func IsUint64Sorted(a []uint64) bool {
   110  	if len(a) == 0 || len(a) == 1 {
   111  		return true
   112  	}
   113  	for i := 1; i < len(a); i++ {
   114  		if a[i-1] > a[i] {
   115  			return false
   116  		}
   117  	}
   118  	return true
   119  }
   120  
   121  // NotUint64 returns the uint64 in slice b that are
   122  // not in slice a with time complexity of approximately
   123  // O(n) leveraging a map to check for element existence
   124  // off by a constant factor of underlying map efficiency.
   125  func NotUint64(a, b []uint64) []uint64 {
   126  	set := make([]uint64, 0)
   127  	m := make(map[uint64]bool)
   128  
   129  	for i := 0; i < len(a); i++ {
   130  		m[a[i]] = true
   131  	}
   132  	for i := 0; i < len(b); i++ {
   133  		if _, found := m[b[i]]; !found {
   134  			set = append(set, b[i])
   135  		}
   136  	}
   137  	return set
   138  }
   139  
   140  // IsInUint64 returns true if a is in b and False otherwise.
   141  func IsInUint64(a uint64, b []uint64) bool {
   142  	for _, v := range b {
   143  		if a == v {
   144  			return true
   145  		}
   146  	}
   147  	return false
   148  }
   149  
   150  // IntersectionInt64 of any number of int64 slices with time
   151  // complexity of approximately O(n) leveraging a map to
   152  // check for element existence off by a constant factor
   153  // of underlying map efficiency.
   154  func IntersectionInt64(s ...[]int64) []int64 {
   155  	if len(s) == 0 {
   156  		return []int64{}
   157  	}
   158  	if len(s) == 1 {
   159  		return s[0]
   160  	}
   161  	intersect := make([]int64, 0)
   162  	m := make(map[int64]int)
   163  	for _, k := range s[0] {
   164  		m[k] = 1
   165  	}
   166  	for i, num := 1, len(s); i < num; i++ {
   167  		for _, k := range s[i] {
   168  			if _, found := m[k]; found && i == m[k] {
   169  				m[k]++
   170  				if m[k] == num {
   171  					intersect = append(intersect, k)
   172  				}
   173  			}
   174  		}
   175  	}
   176  	return intersect
   177  }
   178  
   179  // UnionInt64 of any number of int64 slices with time
   180  // complexity of approximately O(n) leveraging a map to
   181  // check for element existence off by a constant factor
   182  // of underlying map efficiency.
   183  func UnionInt64(s ...[]int64) []int64 {
   184  	if len(s) == 0 {
   185  		return []int64{}
   186  	}
   187  	if len(s) == 1 {
   188  		return s[0]
   189  	}
   190  	set := s[0]
   191  	m := make(map[int64]bool)
   192  	for i := 1; i < len(s); i++ {
   193  		a := s[i-1]
   194  		b := s[i]
   195  		for j := 0; j < len(a); j++ {
   196  			m[a[j]] = true
   197  		}
   198  		for j := 0; j < len(b); j++ {
   199  			if _, found := m[b[j]]; !found {
   200  				set = append(set, b[j])
   201  			}
   202  		}
   203  	}
   204  	return set
   205  }
   206  
   207  // NotInt64 returns the int64 in slice a that are
   208  // not in slice b with time complexity of approximately
   209  // O(n) leveraging a map to check for element existence
   210  // off by a constant factor of underlying map efficiency.
   211  func NotInt64(a, b []int64) []int64 {
   212  	set := make([]int64, 0)
   213  	m := make(map[int64]bool)
   214  
   215  	for i := 0; i < len(a); i++ {
   216  		m[a[i]] = true
   217  	}
   218  	for i := 0; i < len(b); i++ {
   219  		if _, found := m[b[i]]; !found {
   220  			set = append(set, b[i])
   221  		}
   222  	}
   223  	return set
   224  }
   225  
   226  // IsInInt64 returns true if a is in b and False otherwise.
   227  func IsInInt64(a int64, b []int64) bool {
   228  	for _, v := range b {
   229  		if a == v {
   230  			return true
   231  		}
   232  	}
   233  	return false
   234  }
   235  
   236  // UnionByteSlices returns the all elements between sets of byte slices.
   237  func UnionByteSlices(s ...[][]byte) [][]byte {
   238  	if len(s) == 0 {
   239  		return [][]byte{}
   240  	}
   241  	if len(s) == 1 {
   242  		return s[0]
   243  	}
   244  	set := s[0]
   245  	m := make(map[string]bool)
   246  	for i := 1; i < len(s); i++ {
   247  		for j := 0; j < len(s[i-1]); j++ {
   248  			m[string(s[i-1][j])] = true
   249  		}
   250  		for j := 0; j < len(s[i]); j++ {
   251  			if _, found := m[string(s[i][j])]; !found {
   252  				set = append(set, s[i][j])
   253  			}
   254  		}
   255  	}
   256  	return set
   257  }
   258  
   259  // IntersectionByteSlices returns the common elements between sets of byte slices.
   260  func IntersectionByteSlices(s ...[][]byte) [][]byte {
   261  	if len(s) == 0 {
   262  		return [][]byte{}
   263  	}
   264  	if len(s) == 1 {
   265  		return s[0]
   266  	}
   267  	inter := make([][]byte, 0)
   268  	m := make(map[string]int)
   269  	for _, k := range s[0] {
   270  		m[string(k)] = 1
   271  	}
   272  	for i, num := 1, len(s); i < num; i++ {
   273  		for _, k := range s[i] {
   274  			if _, found := m[string(k)]; found && i == m[string(k)] {
   275  				m[string(k)]++
   276  				if m[string(k)] == num {
   277  					inter = append(inter, k)
   278  				}
   279  			}
   280  		}
   281  	}
   282  	return inter
   283  }
   284  
   285  // SplitCommaSeparated values from the list. Example: []string{"a,b", "c,d"} becomes []string{"a", "b", "c", "d"}.
   286  func SplitCommaSeparated(arr []string) []string {
   287  	var result []string
   288  	for _, val := range arr {
   289  		result = append(result, strings.Split(val, ",")...)
   290  	}
   291  	return result
   292  }
   293  
   294  // SplitOffset returns the start index of a given list splits into chunks,
   295  // it computes (listsize * index) / chunks.
   296  //
   297  // Spec pseudocode definition:
   298  // def get_split_offset(list_size: int, chunks: int, index: int) -> int:
   299  //     """
   300  //     Returns a value such that for a list L, chunk count k and index i,
   301  //     split(L, k)[i] == L[get_split_offset(len(L), k, i): get_split_offset(len(L), k, i+1)]
   302  //     """
   303  //     return (list_size * index) // chunks
   304  func SplitOffset(listSize, chunks, index uint64) uint64 {
   305  	return (listSize * index) / chunks
   306  }
   307  
   308  // IntersectionSlot of any number of types.Slot slices with time
   309  // complexity of approximately O(n) leveraging a map to
   310  // check for element existence off by a constant factor
   311  // of underlying map efficiency.
   312  func IntersectionSlot(s ...[]types.Slot) []types.Slot {
   313  	if len(s) == 0 {
   314  		return []types.Slot{}
   315  	}
   316  	if len(s) == 1 {
   317  		return s[0]
   318  	}
   319  	intersect := make([]types.Slot, 0)
   320  	m := make(map[types.Slot]int)
   321  	for _, k := range s[0] {
   322  		m[k] = 1
   323  	}
   324  	for i, num := 1, len(s); i < num; i++ {
   325  		for _, k := range s[i] {
   326  			// Increment and check only if item is present in both, and no increment has happened yet.
   327  			if _, found := m[k]; found && i == m[k] {
   328  				m[k]++
   329  				if m[k] == num {
   330  					intersect = append(intersect, k)
   331  				}
   332  			}
   333  		}
   334  	}
   335  	return intersect
   336  }
   337  
   338  // NotSlot returns the types.Slot in slice b that are
   339  // not in slice a with time complexity of approximately
   340  // O(n) leveraging a map to check for element existence
   341  // off by a constant factor of underlying map efficiency.
   342  func NotSlot(a, b []types.Slot) []types.Slot {
   343  	set := make([]types.Slot, 0)
   344  	m := make(map[types.Slot]bool)
   345  
   346  	for i := 0; i < len(a); i++ {
   347  		m[a[i]] = true
   348  	}
   349  	for i := 0; i < len(b); i++ {
   350  		if _, found := m[b[i]]; !found {
   351  			set = append(set, b[i])
   352  		}
   353  	}
   354  	return set
   355  }
   356  
   357  // IsInSlots returns true if a is in b and False otherwise.
   358  func IsInSlots(a types.Slot, b []types.Slot) bool {
   359  	for _, v := range b {
   360  		if a == v {
   361  			return true
   362  		}
   363  	}
   364  	return false
   365  }