github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zarray/slice.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 package zarray 5 6 import ( 7 "math/rand" 8 9 "github.com/sohaha/zlsgo/zstring" 10 "github.com/sohaha/zlsgo/zsync" 11 "github.com/sohaha/zlsgo/zutil" 12 ) 13 14 // CopySlice copy a slice. 15 func CopySlice[T any](l []T) []T { 16 nl := make([]T, len(l)) 17 copy(nl, l) 18 return nl 19 } 20 21 // Rand A random eents. 22 func Rand[T any](collection []T) T { 23 l := len(collection) 24 if l == 0 { 25 var zero T 26 return zero 27 } 28 29 i := zstring.RandInt(0, l-1) 30 return collection[i] 31 } 32 33 // Map manipulates a slice and transforms it to a slice of another type. 34 func Map[T any, R any](collection []T, iteratee func(int, T) R) []R { 35 res := make([]R, len(collection)) 36 37 for i, item := range collection { 38 res[i] = iteratee(i, item) 39 } 40 41 return res 42 } 43 44 // ParallelMap Parallel manipulates a slice and transforms it to a slice of another type. 45 // If the calculation does not involve time-consuming operations, we recommend using a Map. 46 func ParallelMap[T any, R any](collection []T, iteratee func(int, T) R, workers uint) []R { 47 inLen, workTotal := len(collection), int(workers) 48 49 res := make([]R, inLen) 50 if inLen == 0 { 51 return res 52 } 53 54 if inLen < workTotal { 55 workTotal = inLen 56 } else if workTotal == 0 { 57 workTotal = 1 58 } 59 60 idx := zutil.NewInt64(0) 61 task := func() { 62 i := int(idx.Add(1) - 1) 63 for ; i < inLen; i = int(idx.Add(1) - 1) { 64 res[i] = iteratee(i, collection[i]) 65 } 66 } 67 68 var wg zsync.WaitGroup 69 for i := 0; i < workTotal; i++ { 70 wg.Go(task) 71 } 72 _ = wg.Wait() 73 74 return res 75 } 76 77 // Shuffle creates a slice of shuffled values. 78 func Shuffle[T any](collection []T) []T { 79 n := CopySlice(collection) 80 rand.Shuffle(len(n), func(i, j int) { 81 n[i], n[j] = n[j], n[i] 82 }) 83 84 return n 85 } 86 87 // Reverse creates a slice of reversed values. 88 func Reverse[T any](collection []T) []T { 89 n := CopySlice(collection) 90 l := len(n) 91 for i := 0; i < l/2; i++ { 92 n[i], n[l-i-1] = n[l-i-1], n[i] 93 } 94 95 return n 96 } 97 98 // Filter iterates over eents of collection. 99 func Filter[T any](slice []T, predicate func(index int, item T) bool) []T { 100 slice = CopySlice(slice) 101 102 j := 0 103 for i := range slice { 104 if !predicate(i, slice[i]) { 105 continue 106 } 107 slice[j] = slice[i] 108 j++ 109 } 110 111 return slice[:j:j] 112 } 113 114 // Contains returns true if an eent is present in a collection. 115 func Contains[T comparable](collection []T, v T) bool { 116 for _, item := range collection { 117 if item == v { 118 return true 119 } 120 } 121 122 return false 123 } 124 125 // Find search an eent in a slice based on a predicate. It returns eent and true if eent was found. 126 func Find[T any](collection []T, predicate func(index int, item T) bool) (res T, ok bool) { 127 for i := range collection { 128 item := collection[i] 129 if predicate(i, item) { 130 return item, true 131 } 132 } 133 134 return 135 } 136 137 // Unique returns a duplicate-free version of an array. 138 func Unique[T comparable](collection []T) []T { 139 repeat := make(map[T]struct{}, len(collection)) 140 141 return Filter(collection, func(_ int, item T) bool { 142 if _, ok := repeat[item]; ok { 143 return false 144 } 145 repeat[item] = struct{}{} 146 return true 147 }) 148 } 149 150 // Diff returns the difference between two slices. 151 func Diff[T comparable](list1 []T, list2 []T) ([]T, []T) { 152 l, r := []T{}, []T{} 153 154 rl, rr := map[T]struct{}{}, map[T]struct{}{} 155 156 for _, e := range list1 { 157 rl[e] = struct{}{} 158 } 159 160 for _, e := range list2 { 161 rr[e] = struct{}{} 162 } 163 164 for _, e := range list1 { 165 if _, ok := rr[e]; !ok { 166 l = append(l, e) 167 } 168 } 169 170 for _, e := range list2 { 171 if _, ok := rl[e]; !ok { 172 r = append(r, e) 173 } 174 } 175 176 return l, r 177 } 178 179 // Pop returns an eent and removes it from the slice. 180 func Pop[T comparable](list *[]T) (v T) { 181 l := len(*list) 182 if l == 0 { 183 return 184 } 185 186 v = (*list)[l-1] 187 *list = (*list)[:l-1] 188 return 189 } 190 191 // Shift returns an eent and removes it from the slice. 192 func Shift[T comparable](list *[]T) (v T) { 193 l := len(*list) 194 if l == 0 { 195 return 196 } 197 198 v = (*list)[0] 199 *list = (*list)[1:] 200 return 201 }