├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── example_slice_test.go ├── go.mod ├── go.sum ├── map.go ├── map_test.go ├── slice.go └── slice_test.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.22 20 | 21 | - name: Build 22 | run: go build -v ./... 23 | 24 | - name: Test 25 | run: go test -v ./... 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Emad Elsaid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/emad-elsaid/types)](https://goreportcard.com/report/github.com/emad-elsaid/types) 4 | [![GoDoc](https://godoc.org/github.com/emad-elsaid/types?status.svg)](https://godoc.org/github.com/emad-elsaid/types) 5 | [![codecov](https://codecov.io/gh/emad-elsaid/types/branch/master/graph/badge.svg)](https://codecov.io/gh/emad-elsaid/types) 6 | 7 | Go implementation for generic types, imitating Ruby types 8 | 9 | # Data structures 10 | 11 | ## Slice 12 | 13 | A slice of `comparable` type that can hold any value 14 | 15 | ### Example 16 | 17 | ```go 18 | func ExampleSlice() { 19 | a := Slice[int]{1, 2, 3, 4, 5, 6} 20 | 21 | // multiply every element by 100 22 | a = a.Map(func(e int) int { 23 | return e * 100 24 | }) 25 | 26 | // select any element <= 300 27 | a = a.KeepIf(func(e int) bool { 28 | return e <= 300 29 | }) 30 | 31 | fmt.Print(a) 32 | 33 | // Output: [100 200 300] 34 | } 35 | ``` 36 | 37 | ### Slice Methods available: 38 | 39 | ```go 40 | func (a Slice[T]) All(block func(T) bool) bool 41 | func (a Slice[T]) Any(block func(T) bool) bool 42 | func (a Slice[T]) At(index int) *T 43 | func (a Slice[T]) CountBy(block func(T) bool) (count int) 44 | func (a Slice[T]) CountElement(element T) (count int) 45 | func (a Slice[T]) Cycle(count int, block func(T)) 46 | func (a Slice[T]) Delete(element T) Slice[T] 47 | func (a Slice[T]) DeleteAt(index int) Slice[T] 48 | func (a Slice[T]) DeleteIf(block func(T) bool) Slice[T] 49 | func (a Slice[T]) Drop(count int) Slice[T] 50 | func (a Slice[T]) Each(block func(T)) 51 | func (a Slice[T]) EachIndex(block func(int)) 52 | func (a Slice[T]) Fetch(index int, defaultValue T) T 53 | func (a Slice[T]) Fill(element T, start int, length int) Slice[T] 54 | func (a Slice[T]) FillWith(start int, length int, block func(int) T) Slice[T] 55 | func (a Slice[T]) First() *T 56 | func (a Slice[T]) Firsts(count int) Slice[T] 57 | func (a Slice[T]) Include(element T) bool 58 | func (a Slice[T]) Index(element T) int 59 | func (a Slice[T]) IndexBy(block func(T) bool) int 60 | func (a Slice[T]) Insert(index int, elements ...T) Slice[T] 61 | func (a Slice[T]) IsEmpty() bool 62 | func (a Slice[T]) IsEq(other Slice[T]) bool 63 | func (a Slice[T]) KeepIf(block func(T) bool) Slice[T] 64 | func (a Slice[T]) Last() *T 65 | func (a Slice[T]) Lasts(count int) Slice[T] 66 | func (a Slice[T]) Len() int 67 | func (a Slice[T]) Map(block func(T) T) Slice[T] 68 | func (a Slice[T]) Max(block func(T) int) T 69 | func (a Slice[T]) Min(block func(T) int) T 70 | func (a Slice[T]) Pop() (Slice[T], T) 71 | func (a Slice[T]) Push(element T) Slice[T] 72 | func (a Slice[T]) Reduce(block func(T) bool) Slice[T] 73 | func (a Slice[T]) Reverse() Slice[T] 74 | func (a Slice[T]) Select(block func(T) bool) Slice[T] 75 | func (a Slice[T]) SelectUntil(block func(T) bool) Slice[T] 76 | func (a Slice[T]) Shift() (T, Slice[T]) 77 | func (a Slice[T]) Shuffle() Slice[T] 78 | func (a Slice[T]) Unshift(element T) Slice[T] 79 | ``` 80 | -------------------------------------------------------------------------------- /example_slice_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "fmt" 4 | 5 | func ExampleSlice() { 6 | a := Slice[int]{1, 2, 3, 4, 5, 6} 7 | 8 | // multiply every element by 100 9 | a = a.Map(func(e int) int { 10 | return e * 100 11 | }) 12 | 13 | // select any element <= 300 14 | a = a.KeepIf(func(e int) bool { 15 | return e <= 300 16 | }) 17 | 18 | fmt.Print(a) 19 | 20 | // Output: [100 200 300] 21 | } 22 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/emad-elsaid/types 2 | 3 | go 1.22 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emad-elsaid/types/3bc9fbb889b3e0ebae10b32d2c25d88488741099/go.sum -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "sync" 4 | 5 | // Map is a wrapper for sync.Map with same methods (except for CompareAnd*) 6 | // Check: https://pkg.go.dev/sync#Map 7 | type Map[K comparable, V any] struct { 8 | store sync.Map 9 | } 10 | 11 | func (m *Map[K, V]) Store(k K, v V) { 12 | m.store.Store(k, v) 13 | } 14 | 15 | func (m *Map[K, V]) Load(k K) (v V, ok bool) { 16 | var a any 17 | 18 | a, ok = m.store.Load(k) 19 | if ok { 20 | v = a.(V) 21 | } 22 | 23 | return 24 | } 25 | 26 | // Delete see sync.Map#Delete 27 | func (m *Map[K, V]) Delete(k K) { 28 | m.store.Delete(k) 29 | } 30 | 31 | // Range see sync.Map#Range 32 | func (m *Map[K, V]) Range(f func(k K, v V) bool) { 33 | m.store.Range(func(k, v any) bool { 34 | return f(k.(K), v.(V)) 35 | }) 36 | } 37 | 38 | // LoadAndDelete see sync.Map#LoadAndDelete 39 | func (m *Map[K, V]) LoadAndDelete(k K) (v V, loaded bool) { 40 | var a any 41 | a, loaded = m.store.LoadAndDelete(k) 42 | if loaded { 43 | v = a.(V) 44 | } 45 | 46 | return 47 | } 48 | 49 | // LoadOrStore see sync.Map#LoadOrStore 50 | func (m *Map[K, V]) LoadOrStore(k K, v V) (actual V, loaded bool) { 51 | var a any 52 | a, loaded = m.store.LoadOrStore(k, v) 53 | actual = a.(V) 54 | 55 | return 56 | } 57 | 58 | // Swap see sync.Map#Swap 59 | func (m *Map[K, V]) Swap(k K, v V) (previous V, loaded bool) { 60 | var a any 61 | a, loaded = m.store.Swap(k, v) 62 | previous, _ = a.(V) 63 | 64 | return 65 | } 66 | -------------------------------------------------------------------------------- /map_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "testing" 4 | 5 | func TestMap(t *testing.T) { 6 | t.Run("Store/Load", func(t *testing.T) { 7 | m := Map[string, string]{} 8 | m.Store("Key1", "Value1") 9 | m.Store("Key2", "Value2") 10 | 11 | if v, ok := m.Load("Key1"); v != "Value1" || !ok { 12 | t.Errorf("Expected (%s, %t) but got (%s,%t)", v, ok, v, ok) 13 | } 14 | 15 | if v, ok := m.Load("Key2"); v != "Value2" || !ok { 16 | t.Errorf("Expected (%s, %t) but got (%s,%t)", v, ok, v, ok) 17 | } 18 | 19 | if v, ok := m.Load("Key3"); v != "" || ok { 20 | t.Errorf("Expected (%s, %t) but got (%s,%t)", v, ok, v, ok) 21 | } 22 | }) 23 | 24 | t.Run("Delete", func(t *testing.T) { 25 | m := Map[string, string]{} 26 | m.Store("Key1", "Value1") 27 | m.Delete("Key1") 28 | 29 | if v, ok := m.Load("Key1"); ok { 30 | t.Errorf("Key shouldn't exist but it was found: %v", v) 31 | } 32 | }) 33 | 34 | t.Run("Range", func(t *testing.T) { 35 | m := Map[string, string]{} 36 | m.Store("Key1", "Value1") 37 | m.Store("Key2", "Value2") 38 | 39 | cpy := Map[string, string]{} 40 | m.Range(func(k string, v string) bool { 41 | cpy.Store(k, v) 42 | return true 43 | }) 44 | 45 | if v, ok := cpy.Load("Key1"); v != "Value1" || !ok { 46 | t.Errorf("Expected: Value1, got: %s", v) 47 | } 48 | 49 | if v, ok := cpy.Load("Key2"); v != "Value2" || !ok { 50 | t.Errorf("Expected: Value2, got: %s", v) 51 | } 52 | }) 53 | 54 | t.Run("LoadAndDelete", func(t *testing.T) { 55 | m := Map[string, string]{} 56 | m.Store("Key1", "Value1") 57 | 58 | if v, loaded := m.LoadAndDelete("Key1"); v != "Value1" || !loaded { 59 | t.Errorf("Expected: Value1 and true, got: %s, %t", v, loaded) 60 | } 61 | 62 | if v, loaded := m.LoadAndDelete("Key2"); v != "" || loaded { 63 | t.Errorf("Expected: empty and false, got: %s, %t", v, loaded) 64 | } 65 | }) 66 | 67 | t.Run("LoadOrStore", func(t *testing.T) { 68 | m := Map[string, string]{} 69 | m.Store("Key1", "Value1") 70 | 71 | if v, loaded := m.LoadOrStore("Key1", "Value1/1"); v != "Value1" || !loaded { 72 | t.Errorf("Expected Value1 and loaded, got: %s, %t", v, loaded) 73 | } 74 | 75 | if v, loaded := m.LoadOrStore("Key2", "Value2"); v != "Value2" || loaded { 76 | t.Errorf("Expected Value2 and not loaded, got: %s, %t", v, loaded) 77 | } 78 | }) 79 | 80 | t.Run("Swap", func(t *testing.T) { 81 | m := Map[string, string]{} 82 | m.Store("Key1", "Value1") 83 | 84 | if v, loaded := m.Swap("Key1", "Value1/1"); v != "Value1" || !loaded { 85 | t.Errorf("Expected Value1 and loaded, got: %s, %t", v, loaded) 86 | } 87 | 88 | if v, loaded := m.Swap("Key2", "Value2"); v != "" || loaded { 89 | t.Errorf("Expected Value2 and not loaded, got: %s, %t", v, loaded) 90 | } 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /slice.go: -------------------------------------------------------------------------------- 1 | // Package types provides a generic data types similar to that of Ruby 2 | package types 3 | 4 | import "math/rand" 5 | 6 | // Slice is an alias for a slice of variables that vary in types 7 | // Slice can hold any comparable data type 8 | type Slice[T comparable] []T 9 | 10 | // At returns element by index, a negative index counts from the end of 11 | // the Slice 12 | // if index is out of range it returns nil 13 | func (a Slice[T]) At(index int) *T { 14 | len := len(a) 15 | 16 | if index < 0 { 17 | if -index <= len { 18 | return &a[len+index] 19 | } 20 | return nil 21 | } 22 | 23 | if index < len { 24 | return &a[index] 25 | } 26 | 27 | return nil 28 | } 29 | 30 | // CountElement returns number of elements equal to "element" in Slice 31 | func (a Slice[T]) CountElement(element T) (count int) { 32 | for _, o := range a { 33 | if o == element { 34 | count++ 35 | } 36 | } 37 | return count 38 | } 39 | 40 | // CountBy returns number of elements which "block" returns true for 41 | func (a Slice[T]) CountBy(block func(T) bool) (count int) { 42 | for _, o := range a { 43 | if block(o) { 44 | count++ 45 | } 46 | } 47 | return count 48 | } 49 | 50 | // Cycle will cycle through Slice elements "count" times passing each 51 | // element to "block" function 52 | func (a Slice[T]) Cycle(count int, block func(T)) { 53 | for i := 0; i < count; i++ { 54 | for _, v := range a { 55 | block(v) 56 | } 57 | } 58 | } 59 | 60 | // Any returns true if "block" returned true for any of the Slice elements 61 | // and false otherwise 62 | func (a Slice[T]) Any(block func(T) bool) bool { 63 | for _, o := range a { 64 | if block(o) { 65 | return true 66 | } 67 | } 68 | 69 | return false 70 | } 71 | 72 | // All returns true if "block" returned true for all elements in Slice and 73 | // false otherwise 74 | func (a Slice[T]) All(block func(T) bool) bool { 75 | for _, o := range a { 76 | if !block(o) { 77 | return false 78 | } 79 | } 80 | 81 | return true 82 | } 83 | 84 | // Delete will remove all elements that are equal to the passed element 85 | func (a Slice[T]) Delete(element T) Slice[T] { 86 | result := Slice[T]{} 87 | for _, o := range a { 88 | if o != element { 89 | result = append(result, o) 90 | } 91 | } 92 | return result 93 | } 94 | 95 | // DeleteAt will delete an element by index 96 | func (a Slice[T]) DeleteAt(index int) Slice[T] { 97 | return append(a[:index], a[index+1:]...) 98 | } 99 | 100 | // DeleteIf will delete all elements which "block" returns true for 101 | func (a Slice[T]) DeleteIf(block func(T) bool) Slice[T] { 102 | result := Slice[T]{} 103 | for _, o := range a { 104 | if !block(o) { 105 | result = append(result, o) 106 | } 107 | } 108 | return result 109 | } 110 | 111 | // Drop will return an array without the first "count" elements from the 112 | // beginning 113 | func (a Slice[T]) Drop(count int) Slice[T] { 114 | return a[count:] 115 | } 116 | 117 | // Each will execute "block" for each element in array 118 | func (a Slice[T]) Each(block func(T)) { 119 | for _, o := range a { 120 | block(o) 121 | } 122 | } 123 | 124 | // EachIndex will execute "block" for each element index in array 125 | func (a Slice[T]) EachIndex(block func(int)) { 126 | for i := range a { 127 | block(i) 128 | } 129 | } 130 | 131 | // IsEmpty will return true of array empty, false otherwise 132 | func (a Slice[T]) IsEmpty() bool { 133 | return len(a) == 0 134 | } 135 | 136 | // IsEq returns true if array the "other" array 137 | func (a Slice[T]) IsEq(other Slice[T]) bool { 138 | // check length 139 | if len(a) != len(other) { 140 | return false 141 | } 142 | 143 | // check values 144 | for i, o := range a { 145 | if o != other[i] { 146 | return false 147 | } 148 | } 149 | 150 | return true 151 | } 152 | 153 | // Len returns number of elements in array 154 | func (a Slice[T]) Len() int { 155 | return len(a) 156 | } 157 | 158 | // Fetch will return the element in "index", if it doesn't exist it 159 | // returns the passed "defaultValue" 160 | func (a Slice[T]) Fetch(index int, defaultValue T) T { 161 | val := a.At(index) 162 | if val != nil { 163 | return *val 164 | } 165 | 166 | return defaultValue 167 | } 168 | 169 | // Fill will replace elements inplace starting from "start" counting 170 | // "length" elements with the passed "element" parameter, will return same array 171 | // object 172 | func (a Slice[T]) Fill(element T, start int, length int) Slice[T] { 173 | for length--; length >= 0; length-- { 174 | a[start+length] = element 175 | } 176 | return a 177 | } 178 | 179 | // FillWith will replace elements from start counting "length" items, 180 | // passing every index to block and replacing the element inplace with the 181 | // return value 182 | func (a Slice[T]) FillWith(start int, length int, block func(int) T) Slice[T] { 183 | for length--; length >= 0; length-- { 184 | a[start+length] = block(start + length) 185 | } 186 | return a 187 | } 188 | 189 | // Index returns the index of the first element in array that is equal to 190 | // "element", returns -1 if the elements if not found 191 | func (a Slice[T]) Index(element T) int { 192 | for i, o := range a { 193 | if o == element { 194 | return i 195 | } 196 | } 197 | return -1 198 | } 199 | 200 | // IndexBy returns first element that block returns true for, -1 otherwise 201 | func (a Slice[T]) IndexBy(block func(T) bool) int { 202 | for i, o := range a { 203 | if block(o) { 204 | return i 205 | } 206 | } 207 | 208 | return -1 209 | } 210 | 211 | // First returns first element of array 212 | func (a Slice[T]) First() *T { 213 | return a.At(0) 214 | } 215 | 216 | // Last returns last element of array 217 | func (a Slice[T]) Last() *T { 218 | return a.At(len(a) - 1) 219 | } 220 | 221 | // Firsts will return an array holding the first "count" elements of the 222 | // array 223 | func (a Slice[T]) Firsts(count int) Slice[T] { 224 | return a[0:count] 225 | } 226 | 227 | // Lasts will return an array holding the lasts "count" elements of the 228 | // array 229 | func (a Slice[T]) Lasts(count int) Slice[T] { 230 | return a[len(a)-count:] 231 | } 232 | 233 | // Include will return true if element found in the array 234 | func (a Slice[T]) Include(element T) bool { 235 | return a.Index(element) != -1 236 | } 237 | 238 | // Insert will insert a set of elements in the index and will return a new 239 | // array 240 | func (a Slice[T]) Insert(index int, elements ...T) Slice[T] { 241 | result := Slice[T]{} 242 | result = append(result, a[0:index]...) 243 | result = append(result, elements...) 244 | result = append(result, a[index:]...) 245 | return result 246 | } 247 | 248 | // KeepIf will return an array contains all elements where "block" 249 | // returned true for them 250 | func (a Slice[T]) KeepIf(block func(T) bool) Slice[T] { 251 | result := Slice[T]{} 252 | for _, o := range a { 253 | if block(o) { 254 | result = append(result, o) 255 | } 256 | } 257 | return result 258 | } 259 | 260 | // Select is an alias for KeepIf 261 | func (a Slice[T]) Select(block func(T) bool) Slice[T] { 262 | return a.KeepIf(block) 263 | } 264 | 265 | // SelectUntil selects from the start of the slice until the block returns true, 266 | // excluding the item that returned true. 267 | func (a Slice[T]) SelectUntil(block func(T) bool) Slice[T] { 268 | index := a.IndexBy(block) 269 | if index == -1 { 270 | return a 271 | } 272 | 273 | return a[0:index] 274 | } 275 | 276 | // Reduce is an alias for KeepIf 277 | func (a Slice[T]) Reduce(block func(T) bool) Slice[T] { 278 | return a.KeepIf(block) 279 | } 280 | 281 | // Map will return a new array replacing every element from current array 282 | // with the return value of the block 283 | func (a Slice[T]) Map(block func(T) T) Slice[T] { 284 | result := Slice[T]{} 285 | for _, o := range a { 286 | result = append(result, block(o)) 287 | } 288 | return result 289 | } 290 | 291 | // Max returns the element the returned the highest value when passed to 292 | // block 293 | func (a Slice[T]) Max(block func(T) int) T { 294 | if len(a) == 0 { 295 | return *new(T) 296 | } 297 | var maxElement T = a[0] 298 | var maxScore = block(a[0]) 299 | for _, o := range a[1:] { 300 | score := block(o) 301 | if score > maxScore { 302 | maxElement = o 303 | maxScore = score 304 | } 305 | } 306 | 307 | return maxElement 308 | } 309 | 310 | // Min returns the element the returned the lowest value when passed to 311 | // block 312 | func (a Slice[T]) Min(block func(T) int) T { 313 | if len(a) == 0 { 314 | return *new(T) 315 | } 316 | var minElement T = a[0] 317 | var minScore = block(a[0]) 318 | for _, o := range a[1:] { 319 | score := block(o) 320 | if score < minScore { 321 | minElement = o 322 | minScore = score 323 | } 324 | } 325 | 326 | return minElement 327 | } 328 | 329 | // Push appends an element to the array returning a new modified array 330 | func (a Slice[T]) Push(element T) Slice[T] { 331 | return append(a, element) 332 | } 333 | 334 | // Pop removes the last element from the array, returning new array and 335 | // the element 336 | func (a Slice[T]) Pop() (Slice[T], T) { 337 | return a[:len(a)-1], a[len(a)-1] 338 | } 339 | 340 | // Unshift adds an element to the array returning a new modified array 341 | func (a Slice[T]) Unshift(element T) Slice[T] { 342 | return append(Slice[T]{element}, a...) 343 | } 344 | 345 | // Shift will remove the first element of the array returning the element 346 | // and a modified array 347 | func (a Slice[T]) Shift() (T, Slice[T]) { 348 | if len(a) == 0 { 349 | return *new(T), a 350 | } 351 | return a[0], a[1:] 352 | } 353 | 354 | // Reverse will reverse the array in reverse returning the array reference 355 | // again 356 | func (a Slice[T]) Reverse() Slice[T] { 357 | for i := len(a)/2 - 1; i >= 0; i-- { 358 | opp := len(a) - 1 - i 359 | a[i], a[opp] = a[opp], a[i] 360 | } 361 | return a 362 | } 363 | 364 | // Shuffle will randomly shuffle an array elements order returning array 365 | // reference again 366 | func (a Slice[T]) Shuffle() Slice[T] { 367 | for i := len(a) - 1; i > 0; i-- { 368 | j := rand.Intn(i + 1) 369 | a[i], a[j] = a[j], a[i] 370 | } 371 | return a 372 | } 373 | 374 | // Unique returns a unique list of elements in the slice. order or the result is 375 | // same order of the items in the source slice 376 | func (a Slice[T]) Unique() Slice[T] { 377 | keys := map[T]struct{}{} 378 | out := Slice[T]{} 379 | for _, v := range a { 380 | if _, ok := keys[v]; !ok { 381 | keys[v] = struct{}{} 382 | out = append(out, v) 383 | } 384 | } 385 | 386 | return out 387 | } 388 | -------------------------------------------------------------------------------- /slice_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "testing" 4 | 5 | func AssertSlicesEquals[T comparable](t *testing.T, a1 Slice[T], a2 Slice[T]) { 6 | if len(a1) != len(a2) { 7 | t.Errorf("Slices doesn't have the same length %d, %d", len(a1), len(a2)) 8 | return 9 | } 10 | 11 | for i := range a1 { 12 | if a1[i] != a2[i] { 13 | t.Errorf("Expected (%v) = %v but got %v", i, a1[i], a2[i]) 14 | } 15 | } 16 | } 17 | 18 | func TestSliceAt(t *testing.T) { 19 | a := Slice[int]{1, 2, 3, 4, 5, 6, 7} 20 | tcs := map[int]int{ 21 | 1: 2, 22 | 6: 7, 23 | -1: 7, 24 | -7: 1, 25 | } 26 | 27 | for i, v := range tcs { 28 | result := a.At(i) 29 | if *result != v { 30 | t.Errorf("With %d expected %d but found %d", i, v, result) 31 | } 32 | } 33 | 34 | result := a.At(8) 35 | if result != nil { 36 | t.Errorf("With %d expected %v but found %d", 8, nil, result) 37 | } 38 | } 39 | 40 | func TestSliceLen(t *testing.T) { 41 | a := Slice[int]{1, 2, 3, 4} 42 | result := a.Len() 43 | if result != 4 { 44 | t.Errorf("Expected %d but found %d", 4, result) 45 | } 46 | } 47 | 48 | func TestSliceCountElement(t *testing.T) { 49 | a := Slice[int]{1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3} 50 | tcs := map[int]int{ 51 | 1: 3, 52 | 2: 4, 53 | 3: 5, 54 | 4: 0, 55 | } 56 | 57 | for i, v := range tcs { 58 | result := a.CountElement(i) 59 | if result != v { 60 | t.Errorf("With %d expected %d but found %d", i, v, result) 61 | } 62 | } 63 | } 64 | 65 | func TestSliceCountBy(t *testing.T) { 66 | a := Slice[int]{1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3} 67 | tcs := []struct { 68 | name string 69 | f func(e int) bool 70 | result int 71 | }{ 72 | { 73 | name: "e == 1", 74 | f: func(e int) bool { return e == 1 }, 75 | result: 3, 76 | }, 77 | { 78 | name: "e < 1", 79 | f: func(e int) bool { return e < 1 }, 80 | result: 0, 81 | }, 82 | { 83 | name: "e > 1", 84 | f: func(e int) bool { return e > 1 }, 85 | result: 9, 86 | }, 87 | } 88 | 89 | for _, tc := range tcs { 90 | result := a.CountBy(tc.f) 91 | if result != tc.result { 92 | t.Errorf("With %s expected %d but found %d", tc.name, tc.result, result) 93 | } 94 | } 95 | } 96 | 97 | func TestSliceCycle(t *testing.T) { 98 | a := Slice[int]{1, 2} 99 | 100 | elements := []int{1, 2, 1, 2, 1, 2} 101 | a.Cycle(3, func(e int) { 102 | result := e 103 | if result != elements[0] { 104 | t.Errorf("Expected %d but found %d", elements[0], result) 105 | } 106 | 107 | elements = elements[1:] 108 | }) 109 | } 110 | 111 | func TestSliceAny(t *testing.T) { 112 | a := Slice[bool]{false, false, false} 113 | identity := func(e bool) bool { 114 | return e 115 | } 116 | if a.Any(identity) { 117 | t.Error("Expected false but got true") 118 | } 119 | 120 | a = Slice[bool]{false, true, false} 121 | if !a.Any(identity) { 122 | t.Error("Expected true but got false") 123 | } 124 | } 125 | 126 | func TestSliceAll(t *testing.T) { 127 | a := Slice[bool]{true, true, true} 128 | identity := func(e bool) bool { 129 | return e 130 | } 131 | if !a.All(identity) { 132 | t.Error("Expected true but got false") 133 | } 134 | 135 | a = Slice[bool]{false, true, false} 136 | if a.All(identity) { 137 | t.Error("Expected false but got true") 138 | } 139 | } 140 | 141 | func TestSliceDelete(t *testing.T) { 142 | a := Slice[int]{1, 2, 3, 4, 1, 2, 3, 4} 143 | a = a.Delete(1) 144 | result := Slice[int]{2, 3, 4, 2, 3, 4} 145 | AssertSlicesEquals(t, result, a) 146 | } 147 | 148 | func TestSliceDeleteAt(t *testing.T) { 149 | a := Slice[int]{1, 2, 3, 4} 150 | a = a.DeleteAt(1) 151 | result := Slice[int]{1, 3, 4} 152 | AssertSlicesEquals(t, result, a) 153 | } 154 | 155 | func TestSliceDeleteIf(t *testing.T) { 156 | a := Slice[int]{1, 2, 3, 4, 5, 6} 157 | a = a.DeleteIf(func(e int) bool { 158 | return e > 1 159 | }) 160 | result := Slice[int]{1} 161 | AssertSlicesEquals(t, result, a) 162 | } 163 | 164 | func TestSliceDrop(t *testing.T) { 165 | a := Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9} 166 | a = a.Drop(5) 167 | result := Slice[int]{6, 7, 8, 9} 168 | AssertSlicesEquals(t, result, a) 169 | } 170 | 171 | func TestSliceEach(t *testing.T) { 172 | a := Slice[int]{1, 2, 3} 173 | sum := 0 174 | summer := func(e int) { sum += e } 175 | a.Each(summer) 176 | 177 | if sum != 6 { 178 | t.Errorf("Expected sum to be 6 but found %d", sum) 179 | } 180 | } 181 | 182 | func TestSliceEachIndex(t *testing.T) { 183 | a := Slice[int]{1, 2, 3} 184 | var sum int 185 | summer := func(i int) { sum += i } 186 | a.EachIndex(summer) 187 | 188 | if sum != 3 { 189 | t.Errorf("Expected sum to be 3 but found %d", sum) 190 | } 191 | } 192 | 193 | func TestSliceIsEmpty(t *testing.T) { 194 | a := Slice[int]{} 195 | if !a.IsEmpty() { 196 | t.Error("Expected to be empty but found not empty") 197 | } 198 | 199 | a = Slice[int]{1, 2, 3} 200 | if a.IsEmpty() { 201 | t.Error("Expected to be not empty but found empty") 202 | } 203 | } 204 | 205 | func TestSliceIsEq(t *testing.T) { 206 | a := Slice[int]{1, 2, 3, 4} 207 | b := Slice[int]{1, 2, 3, 4} 208 | 209 | if !a.IsEq(b) { 210 | t.Error("Expected arrat a to equal b but found otherwise") 211 | } 212 | } 213 | 214 | func TestSliceFetch(t *testing.T) { 215 | a := Slice[int]{1, 2} 216 | 217 | result := a.Fetch(0, -1) 218 | if result != 1 { 219 | t.Errorf("Expected 1 but got %d", result) 220 | } 221 | 222 | result = a.Fetch(-1, -1) 223 | if result != 2 { 224 | t.Errorf("Expected 2 but bot %d", result) 225 | } 226 | 227 | result = a.Fetch(3, -1) 228 | if result != -1 { 229 | t.Errorf("Expecte default value but got %d", result) 230 | } 231 | } 232 | 233 | func TestSliceFill(t *testing.T) { 234 | a := Slice[int]{1, 2, 3, 4, 5, 6} 235 | result := Slice[int]{1, 2, 1, 1, 1, 6} 236 | a.Fill(1, 2, 3) 237 | AssertSlicesEquals(t, result, a) 238 | } 239 | 240 | func TestSliceFillWith(t *testing.T) { 241 | a := Slice[int]{1, 2, 3, 4, 5, 6} 242 | result := Slice[int]{1, 2, 200, 300, 400, 6} 243 | a.FillWith(2, 3, func(i int) int { 244 | return i * 100 245 | }) 246 | AssertSlicesEquals(t, result, a) 247 | } 248 | 249 | func TestSliceIndex(t *testing.T) { 250 | a := Slice[int]{1, 2, 3, 4, 5, 6} 251 | if a.Index(1) != 0 { 252 | t.Errorf("Expected 1 to have index of 0 but got %d", a.Index(1)) 253 | } 254 | 255 | if a.Index(7) != -1 { 256 | t.Errorf("Expected 7 to have index of -1 gut git %d", a.Index(7)) 257 | } 258 | } 259 | 260 | func TestSliceIndexBy(t *testing.T) { 261 | a := Slice[int]{1, 2, 3, 4, 5, 6} 262 | index := a.IndexBy(func(element int) bool { 263 | return element > 2 264 | }) 265 | if index != 2 { 266 | t.Errorf("Expected element 3 index to be 2 got %d instead", index) 267 | } 268 | 269 | index = a.IndexBy(func(element int) bool { 270 | return element == -1 271 | }) 272 | if index != -1 { 273 | t.Errorf("Expected element -1 index to be -1 go %d instead", index) 274 | } 275 | } 276 | 277 | func TestSliceFirst(t *testing.T) { 278 | a := Slice[int]{1, 2, 3, 4} 279 | if *a.First() != 1 { 280 | t.Errorf("Expected first element to be 1 got %d", a.First()) 281 | } 282 | 283 | a = Slice[int]{} 284 | if a.First() != nil { 285 | t.Errorf("Expected first element to be nil got %d", a.First()) 286 | } 287 | } 288 | 289 | func TestSliceLast(t *testing.T) { 290 | a := Slice[int]{1, 2, 3, 4} 291 | if *a.Last() != 4 { 292 | t.Errorf("Expected last element to be 4 got %d", a.Last()) 293 | } 294 | 295 | a = Slice[int]{} 296 | if a.Last() != nil { 297 | t.Errorf("Expected last element to be nil got %d", a.Last()) 298 | } 299 | } 300 | 301 | func TestSliceFirsts(t *testing.T) { 302 | a := Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9} 303 | result := Slice[int]{1, 2, 3} 304 | AssertSlicesEquals(t, result, a.Firsts(3)) 305 | } 306 | 307 | func TestSliceLasts(t *testing.T) { 308 | a := Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9} 309 | result := Slice[int]{7, 8, 9} 310 | AssertSlicesEquals(t, result, a.Lasts(3)) 311 | } 312 | 313 | func TestSliceInclude(t *testing.T) { 314 | a := Slice[int]{1, 2, 3, 4} 315 | if !a.Include(1) { 316 | t.Error("Expected 1 to be found but didn't find it") 317 | } 318 | 319 | if a.Include(-1) { 320 | t.Error("Expected the string not to be found but it was found!") 321 | } 322 | } 323 | 324 | func TestSliceInsert(t *testing.T) { 325 | a := Slice[int]{1, 2, 3, 4} 326 | result := Slice[int]{1, 2, 0, 3, 4} 327 | b := a.Insert(2, 0) 328 | AssertSlicesEquals(t, result, b) 329 | 330 | result = Slice[int]{1, 2, 3, 4, 0} 331 | c := a.Insert(4, 0) 332 | AssertSlicesEquals(t, result, c) 333 | 334 | result = Slice[int]{0, 1, 2, 3, 4} 335 | d := a.Insert(0, 0) 336 | AssertSlicesEquals(t, result, d) 337 | } 338 | 339 | func TestSliceKeepIf(t *testing.T) { 340 | a := Slice[int]{1, 2, 3, 4, 5, 6} 341 | a = a.KeepIf(func(e int) bool { 342 | return e > 3 343 | }) 344 | result := Slice[int]{4, 5, 6} 345 | AssertSlicesEquals(t, result, a) 346 | } 347 | 348 | func TestSliceSelect(t *testing.T) { 349 | a := Slice[int]{1, 2, 3, 4, 5, 6} 350 | a = a.Select(func(e int) bool { 351 | return e > 3 352 | }) 353 | result := Slice[int]{4, 5, 6} 354 | AssertSlicesEquals(t, result, a) 355 | } 356 | 357 | func TestSliceSelectUntil(t *testing.T) { 358 | a := Slice[int]{1, 2, 3, 4, 5, 6} 359 | a = a.SelectUntil(func(e int) bool { 360 | return e == 3 361 | }) 362 | result := Slice[int]{1, 2} 363 | AssertSlicesEquals(t, result, a) 364 | } 365 | 366 | func TestSliceReduce(t *testing.T) { 367 | a := Slice[int]{1, 2, 3, 4, 5, 6} 368 | a = a.Reduce(func(e int) bool { 369 | return e > 3 370 | }) 371 | result := Slice[int]{4, 5, 6} 372 | AssertSlicesEquals(t, result, a) 373 | } 374 | 375 | func TestSliceMap(t *testing.T) { 376 | a := Slice[int]{1, 2, 3, 4, 5} 377 | inc := func(e int) int { 378 | return e + 100 379 | } 380 | result := Slice[int]{101, 102, 103, 104, 105} 381 | AssertSlicesEquals(t, result, a.Map(inc)) 382 | } 383 | 384 | func TestSliceMax(t *testing.T) { 385 | a := Slice[int]{1, 2, 3, 4} 386 | identity := func(e int) int { 387 | return e 388 | } 389 | 390 | result := a.Max(identity) 391 | if result != 4 { 392 | t.Errorf("Expected max to be 4 found %d", result) 393 | } 394 | 395 | a = Slice[int]{} 396 | result = a.Max(identity) 397 | if result != 0 { 398 | t.Errorf("Expected max of empty array to be nil got %d", result) 399 | } 400 | } 401 | 402 | func TestSliceMin(t *testing.T) { 403 | a := Slice[int]{4, 3, 2, 1} 404 | identity := func(e int) int { 405 | return e 406 | } 407 | 408 | result := a.Min(identity) 409 | if result != 1 { 410 | t.Errorf("Expected min to be 4 found %d", result) 411 | } 412 | 413 | a = Slice[int]{} 414 | result = a.Min(identity) 415 | if result != 0 { 416 | t.Errorf("Expected min of empty array to be %d", result) 417 | } 418 | } 419 | 420 | func TestSlicePush(t *testing.T) { 421 | a := Slice[int]{1, 2} 422 | a = a.Push(3) 423 | result := Slice[int]{1, 2, 3} 424 | AssertSlicesEquals(t, result, a) 425 | } 426 | 427 | func TestSlicePop(t *testing.T) { 428 | a := Slice[int]{1, 2, 3} 429 | a, e := a.Pop() 430 | result := Slice[int]{1, 2} 431 | if e != 3 { 432 | t.Errorf("Expected element to be 3 got %d", e) 433 | } 434 | AssertSlicesEquals(t, result, a) 435 | } 436 | 437 | func TestSliceUnshift(t *testing.T) { 438 | a := Slice[int]{1, 2, 3} 439 | a = a.Unshift(4) 440 | result := Slice[int]{4, 1, 2, 3} 441 | AssertSlicesEquals(t, result, a) 442 | } 443 | 444 | func TestSliceShift(t *testing.T) { 445 | a := Slice[int]{1, 2, 3} 446 | e, a := a.Shift() 447 | result := Slice[int]{2, 3} 448 | AssertSlicesEquals(t, result, a) 449 | if e != 1 { 450 | t.Errorf("Expected element to be 1 got %d", e) 451 | } 452 | 453 | a = Slice[int]{} 454 | e, a = a.Shift() 455 | if e != 0 { 456 | t.Errorf("Expected element to be nil got %d", e) 457 | } 458 | } 459 | 460 | func TestSliceReverse(t *testing.T) { 461 | a := Slice[int]{1, 2, 3} 462 | a = a.Reverse() 463 | result := Slice[int]{3, 2, 1} 464 | AssertSlicesEquals(t, result, a) 465 | } 466 | 467 | func TestSliceShuffle(t *testing.T) { 468 | a := Slice[int]{1, 2, 3, 4} 469 | a = a.Shuffle() 470 | notResult := Slice[int]{1, 2, 3, 4} 471 | if a.IsEq(notResult) { 472 | t.Error("Expected arrays not to equal after shuffle but it was the same") 473 | } 474 | } 475 | 476 | func TestSliceUnique(t *testing.T) { 477 | a := Slice[int]{1, 2, 1, 3, 1, 2, 3, 4} 478 | a = a.Unique() 479 | result := Slice[int]{1, 2, 3, 4} 480 | AssertSlicesEquals(t, result, a) 481 | } 482 | --------------------------------------------------------------------------------