github.com/gogf/gf@v1.16.9/container/garray/garray_sorted_int.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package garray 8 9 import ( 10 "bytes" 11 "fmt" 12 "github.com/gogf/gf/internal/json" 13 "math" 14 "sort" 15 16 "github.com/gogf/gf/internal/rwmutex" 17 "github.com/gogf/gf/util/gconv" 18 "github.com/gogf/gf/util/grand" 19 ) 20 21 // SortedIntArray is a golang sorted int array with rich features. 22 // It is using increasing order in default, which can be changed by 23 // setting it a custom comparator. 24 // It contains a concurrent-safe/unsafe switch, which should be set 25 // when its initialization and cannot be changed then. 26 type SortedIntArray struct { 27 mu rwmutex.RWMutex 28 array []int 29 unique bool // Whether enable unique feature(false) 30 comparator func(a, b int) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b) 31 } 32 33 // NewSortedIntArray creates and returns an empty sorted array. 34 // The parameter `safe` is used to specify whether using array in concurrent-safety, 35 // which is false in default. 36 func NewSortedIntArray(safe ...bool) *SortedIntArray { 37 return NewSortedIntArraySize(0, safe...) 38 } 39 40 // NewSortedIntArrayComparator creates and returns an empty sorted array with specified comparator. 41 // The parameter `safe` is used to specify whether using array in concurrent-safety which is false in default. 42 func NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *SortedIntArray { 43 array := NewSortedIntArray(safe...) 44 array.comparator = comparator 45 return array 46 } 47 48 // NewSortedIntArraySize create and returns an sorted array with given size and cap. 49 // The parameter `safe` is used to specify whether using array in concurrent-safety, 50 // which is false in default. 51 func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray { 52 return &SortedIntArray{ 53 mu: rwmutex.Create(safe...), 54 array: make([]int, 0, cap), 55 comparator: defaultComparatorInt, 56 } 57 } 58 59 // NewSortedIntArrayRange creates and returns a array by a range from `start` to `end` 60 // with step value `step`. 61 func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray { 62 if step == 0 { 63 panic(fmt.Sprintf(`invalid step value: %d`, step)) 64 } 65 slice := make([]int, (end-start+1)/step) 66 index := 0 67 for i := start; i <= end; i += step { 68 slice[index] = i 69 index++ 70 } 71 return NewSortedIntArrayFrom(slice, safe...) 72 } 73 74 // NewSortedIntArrayFrom creates and returns an sorted array with given slice `array`. 75 // The parameter `safe` is used to specify whether using array in concurrent-safety, 76 // which is false in default. 77 func NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray { 78 a := NewSortedIntArraySize(0, safe...) 79 a.array = array 80 sort.Ints(a.array) 81 return a 82 } 83 84 // NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice `array`. 85 // The parameter `safe` is used to specify whether using array in concurrent-safety, 86 // which is false in default. 87 func NewSortedIntArrayFromCopy(array []int, safe ...bool) *SortedIntArray { 88 newArray := make([]int, len(array)) 89 copy(newArray, array) 90 return NewSortedIntArrayFrom(newArray, safe...) 91 } 92 93 // At returns the value by the specified index. 94 // If the given `index` is out of range of the array, it returns `0`. 95 func (a *SortedIntArray) At(index int) (value int) { 96 value, _ = a.Get(index) 97 return 98 } 99 100 // SetArray sets the underlying slice array with the given `array`. 101 func (a *SortedIntArray) SetArray(array []int) *SortedIntArray { 102 a.mu.Lock() 103 defer a.mu.Unlock() 104 a.array = array 105 quickSortInt(a.array, a.getComparator()) 106 return a 107 } 108 109 // Sort sorts the array in increasing order. 110 // The parameter `reverse` controls whether sort 111 // in increasing order(default) or decreasing order. 112 func (a *SortedIntArray) Sort() *SortedIntArray { 113 a.mu.Lock() 114 defer a.mu.Unlock() 115 quickSortInt(a.array, a.getComparator()) 116 return a 117 } 118 119 // Add adds one or multiple values to sorted array, the array always keeps sorted. 120 // It's alias of function Append, see Append. 121 func (a *SortedIntArray) Add(values ...int) *SortedIntArray { 122 return a.Append(values...) 123 } 124 125 // Append adds one or multiple values to sorted array, the array always keeps sorted. 126 func (a *SortedIntArray) Append(values ...int) *SortedIntArray { 127 if len(values) == 0 { 128 return a 129 } 130 a.mu.Lock() 131 defer a.mu.Unlock() 132 for _, value := range values { 133 index, cmp := a.binSearch(value, false) 134 if a.unique && cmp == 0 { 135 continue 136 } 137 if index < 0 { 138 a.array = append(a.array, value) 139 continue 140 } 141 if cmp > 0 { 142 index++ 143 } 144 rear := append([]int{}, a.array[index:]...) 145 a.array = append(a.array[0:index], value) 146 a.array = append(a.array, rear...) 147 } 148 return a 149 } 150 151 // Get returns the value by the specified index. 152 // If the given `index` is out of range of the array, the `found` is false. 153 func (a *SortedIntArray) Get(index int) (value int, found bool) { 154 a.mu.RLock() 155 defer a.mu.RUnlock() 156 if index < 0 || index >= len(a.array) { 157 return 0, false 158 } 159 return a.array[index], true 160 } 161 162 // Remove removes an item by index. 163 // If the given `index` is out of range of the array, the `found` is false. 164 func (a *SortedIntArray) Remove(index int) (value int, found bool) { 165 a.mu.Lock() 166 defer a.mu.Unlock() 167 return a.doRemoveWithoutLock(index) 168 } 169 170 // doRemoveWithoutLock removes an item by index without lock. 171 func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool) { 172 if index < 0 || index >= len(a.array) { 173 return 0, false 174 } 175 // Determine array boundaries when deleting to improve deletion efficiency. 176 if index == 0 { 177 value := a.array[0] 178 a.array = a.array[1:] 179 return value, true 180 } else if index == len(a.array)-1 { 181 value := a.array[index] 182 a.array = a.array[:index] 183 return value, true 184 } 185 // If it is a non-boundary delete, 186 // it will involve the creation of an array, 187 // then the deletion is less efficient. 188 value = a.array[index] 189 a.array = append(a.array[:index], a.array[index+1:]...) 190 return value, true 191 } 192 193 // RemoveValue removes an item by value. 194 // It returns true if value is found in the array, or else false if not found. 195 func (a *SortedIntArray) RemoveValue(value int) bool { 196 if i := a.Search(value); i != -1 { 197 _, found := a.Remove(i) 198 return found 199 } 200 return false 201 } 202 203 // PopLeft pops and returns an item from the beginning of array. 204 // Note that if the array is empty, the `found` is false. 205 func (a *SortedIntArray) PopLeft() (value int, found bool) { 206 a.mu.Lock() 207 defer a.mu.Unlock() 208 if len(a.array) == 0 { 209 return 0, false 210 } 211 value = a.array[0] 212 a.array = a.array[1:] 213 return value, true 214 } 215 216 // PopRight pops and returns an item from the end of array. 217 // Note that if the array is empty, the `found` is false. 218 func (a *SortedIntArray) PopRight() (value int, found bool) { 219 a.mu.Lock() 220 defer a.mu.Unlock() 221 index := len(a.array) - 1 222 if index < 0 { 223 return 0, false 224 } 225 value = a.array[index] 226 a.array = a.array[:index] 227 return value, true 228 } 229 230 // PopRand randomly pops and return an item out of array. 231 // Note that if the array is empty, the `found` is false. 232 func (a *SortedIntArray) PopRand() (value int, found bool) { 233 a.mu.Lock() 234 defer a.mu.Unlock() 235 return a.doRemoveWithoutLock(grand.Intn(len(a.array))) 236 } 237 238 // PopRands randomly pops and returns `size` items out of array. 239 // If the given `size` is greater than size of the array, it returns all elements of the array. 240 // Note that if given `size` <= 0 or the array is empty, it returns nil. 241 func (a *SortedIntArray) PopRands(size int) []int { 242 a.mu.Lock() 243 defer a.mu.Unlock() 244 if size <= 0 || len(a.array) == 0 { 245 return nil 246 } 247 if size >= len(a.array) { 248 size = len(a.array) 249 } 250 array := make([]int, size) 251 for i := 0; i < size; i++ { 252 array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array))) 253 } 254 return array 255 } 256 257 // PopLefts pops and returns `size` items from the beginning of array. 258 // If the given `size` is greater than size of the array, it returns all elements of the array. 259 // Note that if given `size` <= 0 or the array is empty, it returns nil. 260 func (a *SortedIntArray) PopLefts(size int) []int { 261 a.mu.Lock() 262 defer a.mu.Unlock() 263 if size <= 0 || len(a.array) == 0 { 264 return nil 265 } 266 if size >= len(a.array) { 267 array := a.array 268 a.array = a.array[:0] 269 return array 270 } 271 value := a.array[0:size] 272 a.array = a.array[size:] 273 return value 274 } 275 276 // PopRights pops and returns `size` items from the end of array. 277 // If the given `size` is greater than size of the array, it returns all elements of the array. 278 // Note that if given `size` <= 0 or the array is empty, it returns nil. 279 func (a *SortedIntArray) PopRights(size int) []int { 280 a.mu.Lock() 281 defer a.mu.Unlock() 282 if size <= 0 || len(a.array) == 0 { 283 return nil 284 } 285 index := len(a.array) - size 286 if index <= 0 { 287 array := a.array 288 a.array = a.array[:0] 289 return array 290 } 291 value := a.array[index:] 292 a.array = a.array[:index] 293 return value 294 } 295 296 // Range picks and returns items by range, like array[start:end]. 297 // Notice, if in concurrent-safe usage, it returns a copy of slice; 298 // else a pointer to the underlying data. 299 // 300 // If `end` is negative, then the offset will start from the end of array. 301 // If `end` is omitted, then the sequence will have everything from start up 302 // until the end of the array. 303 func (a *SortedIntArray) Range(start int, end ...int) []int { 304 a.mu.RLock() 305 defer a.mu.RUnlock() 306 offsetEnd := len(a.array) 307 if len(end) > 0 && end[0] < offsetEnd { 308 offsetEnd = end[0] 309 } 310 if start > offsetEnd { 311 return nil 312 } 313 if start < 0 { 314 start = 0 315 } 316 array := ([]int)(nil) 317 if a.mu.IsSafe() { 318 array = make([]int, offsetEnd-start) 319 copy(array, a.array[start:offsetEnd]) 320 } else { 321 array = a.array[start:offsetEnd] 322 } 323 return array 324 } 325 326 // SubSlice returns a slice of elements from the array as specified 327 // by the `offset` and `size` parameters. 328 // If in concurrent safe usage, it returns a copy of the slice; else a pointer. 329 // 330 // If offset is non-negative, the sequence will start at that offset in the array. 331 // If offset is negative, the sequence will start that far from the end of the array. 332 // 333 // If length is given and is positive, then the sequence will have up to that many elements in it. 334 // If the array is shorter than the length, then only the available array elements will be present. 335 // If length is given and is negative then the sequence will stop that many elements from the end of the array. 336 // If it is omitted, then the sequence will have everything from offset up until the end of the array. 337 // 338 // Any possibility crossing the left border of array, it will fail. 339 func (a *SortedIntArray) SubSlice(offset int, length ...int) []int { 340 a.mu.RLock() 341 defer a.mu.RUnlock() 342 size := len(a.array) 343 if len(length) > 0 { 344 size = length[0] 345 } 346 if offset > len(a.array) { 347 return nil 348 } 349 if offset < 0 { 350 offset = len(a.array) + offset 351 if offset < 0 { 352 return nil 353 } 354 } 355 if size < 0 { 356 offset += size 357 size = -size 358 if offset < 0 { 359 return nil 360 } 361 } 362 end := offset + size 363 if end > len(a.array) { 364 end = len(a.array) 365 size = len(a.array) - offset 366 } 367 if a.mu.IsSafe() { 368 s := make([]int, size) 369 copy(s, a.array[offset:]) 370 return s 371 } else { 372 return a.array[offset:end] 373 } 374 } 375 376 // Len returns the length of array. 377 func (a *SortedIntArray) Len() int { 378 a.mu.RLock() 379 length := len(a.array) 380 a.mu.RUnlock() 381 return length 382 } 383 384 // Sum returns the sum of values in an array. 385 func (a *SortedIntArray) Sum() (sum int) { 386 a.mu.RLock() 387 defer a.mu.RUnlock() 388 for _, v := range a.array { 389 sum += v 390 } 391 return 392 } 393 394 // Slice returns the underlying data of array. 395 // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data, 396 // or else a pointer to the underlying data. 397 func (a *SortedIntArray) Slice() []int { 398 array := ([]int)(nil) 399 if a.mu.IsSafe() { 400 a.mu.RLock() 401 defer a.mu.RUnlock() 402 array = make([]int, len(a.array)) 403 copy(array, a.array) 404 } else { 405 array = a.array 406 } 407 return array 408 } 409 410 // Interfaces returns current array as []interface{}. 411 func (a *SortedIntArray) Interfaces() []interface{} { 412 a.mu.RLock() 413 defer a.mu.RUnlock() 414 array := make([]interface{}, len(a.array)) 415 for k, v := range a.array { 416 array[k] = v 417 } 418 return array 419 } 420 421 // Contains checks whether a value exists in the array. 422 func (a *SortedIntArray) Contains(value int) bool { 423 return a.Search(value) != -1 424 } 425 426 // Search searches array by `value`, returns the index of `value`, 427 // or returns -1 if not exists. 428 func (a *SortedIntArray) Search(value int) (index int) { 429 if i, r := a.binSearch(value, true); r == 0 { 430 return i 431 } 432 return -1 433 } 434 435 // Binary search. 436 // It returns the last compared index and the result. 437 // If `result` equals to 0, it means the value at `index` is equals to `value`. 438 // If `result` lesser than 0, it means the value at `index` is lesser than `value`. 439 // If `result` greater than 0, it means the value at `index` is greater than `value`. 440 func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int) { 441 if lock { 442 a.mu.RLock() 443 defer a.mu.RUnlock() 444 } 445 if len(a.array) == 0 { 446 return -1, -2 447 } 448 min := 0 449 max := len(a.array) - 1 450 mid := 0 451 cmp := -2 452 for min <= max { 453 mid = min + int((max-min)/2) 454 cmp = a.getComparator()(value, a.array[mid]) 455 switch { 456 case cmp < 0: 457 max = mid - 1 458 case cmp > 0: 459 min = mid + 1 460 default: 461 return mid, cmp 462 } 463 } 464 return mid, cmp 465 } 466 467 // SetUnique sets unique mark to the array, 468 // which means it does not contain any repeated items. 469 // It also do unique check, remove all repeated items. 470 func (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray { 471 oldUnique := a.unique 472 a.unique = unique 473 if unique && oldUnique != unique { 474 a.Unique() 475 } 476 return a 477 } 478 479 // Unique uniques the array, clear repeated items. 480 func (a *SortedIntArray) Unique() *SortedIntArray { 481 a.mu.Lock() 482 defer a.mu.Unlock() 483 if len(a.array) == 0 { 484 return a 485 } 486 i := 0 487 for { 488 if i == len(a.array)-1 { 489 break 490 } 491 if a.getComparator()(a.array[i], a.array[i+1]) == 0 { 492 a.array = append(a.array[:i+1], a.array[i+1+1:]...) 493 } else { 494 i++ 495 } 496 } 497 return a 498 } 499 500 // Clone returns a new array, which is a copy of current array. 501 func (a *SortedIntArray) Clone() (newArray *SortedIntArray) { 502 a.mu.RLock() 503 array := make([]int, len(a.array)) 504 copy(array, a.array) 505 a.mu.RUnlock() 506 return NewSortedIntArrayFrom(array, a.mu.IsSafe()) 507 } 508 509 // Clear deletes all items of current array. 510 func (a *SortedIntArray) Clear() *SortedIntArray { 511 a.mu.Lock() 512 if len(a.array) > 0 { 513 a.array = make([]int, 0) 514 } 515 a.mu.Unlock() 516 return a 517 } 518 519 // LockFunc locks writing by callback function `f`. 520 func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray { 521 a.mu.Lock() 522 defer a.mu.Unlock() 523 f(a.array) 524 return a 525 } 526 527 // RLockFunc locks reading by callback function `f`. 528 func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray { 529 a.mu.RLock() 530 defer a.mu.RUnlock() 531 f(a.array) 532 return a 533 } 534 535 // Merge merges `array` into current array. 536 // The parameter `array` can be any garray or slice type. 537 // The difference between Merge and Append is Append supports only specified slice type, 538 // but Merge supports more parameter types. 539 func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray { 540 return a.Add(gconv.Ints(array)...) 541 } 542 543 // Chunk splits an array into multiple arrays, 544 // the size of each array is determined by `size`. 545 // The last chunk may contain less than size elements. 546 func (a *SortedIntArray) Chunk(size int) [][]int { 547 if size < 1 { 548 return nil 549 } 550 a.mu.RLock() 551 defer a.mu.RUnlock() 552 length := len(a.array) 553 chunks := int(math.Ceil(float64(length) / float64(size))) 554 var n [][]int 555 for i, end := 0, 0; chunks > 0; chunks-- { 556 end = (i + 1) * size 557 if end > length { 558 end = length 559 } 560 n = append(n, a.array[i*size:end]) 561 i++ 562 } 563 return n 564 } 565 566 // Rand randomly returns one item from array(no deleting). 567 func (a *SortedIntArray) Rand() (value int, found bool) { 568 a.mu.RLock() 569 defer a.mu.RUnlock() 570 if len(a.array) == 0 { 571 return 0, false 572 } 573 return a.array[grand.Intn(len(a.array))], true 574 } 575 576 // Rands randomly returns `size` items from array(no deleting). 577 func (a *SortedIntArray) Rands(size int) []int { 578 a.mu.RLock() 579 defer a.mu.RUnlock() 580 if size <= 0 || len(a.array) == 0 { 581 return nil 582 } 583 array := make([]int, size) 584 for i := 0; i < size; i++ { 585 array[i] = a.array[grand.Intn(len(a.array))] 586 } 587 return array 588 } 589 590 // Join joins array elements with a string `glue`. 591 func (a *SortedIntArray) Join(glue string) string { 592 a.mu.RLock() 593 defer a.mu.RUnlock() 594 if len(a.array) == 0 { 595 return "" 596 } 597 buffer := bytes.NewBuffer(nil) 598 for k, v := range a.array { 599 buffer.WriteString(gconv.String(v)) 600 if k != len(a.array)-1 { 601 buffer.WriteString(glue) 602 } 603 } 604 return buffer.String() 605 } 606 607 // CountValues counts the number of occurrences of all values in the array. 608 func (a *SortedIntArray) CountValues() map[int]int { 609 m := make(map[int]int) 610 a.mu.RLock() 611 defer a.mu.RUnlock() 612 for _, v := range a.array { 613 m[v]++ 614 } 615 return m 616 } 617 618 // Iterator is alias of IteratorAsc. 619 func (a *SortedIntArray) Iterator(f func(k int, v int) bool) { 620 a.IteratorAsc(f) 621 } 622 623 // IteratorAsc iterates the array readonly in ascending order with given callback function `f`. 624 // If `f` returns true, then it continues iterating; or false to stop. 625 func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) { 626 a.mu.RLock() 627 defer a.mu.RUnlock() 628 for k, v := range a.array { 629 if !f(k, v) { 630 break 631 } 632 } 633 } 634 635 // IteratorDesc iterates the array readonly in descending order with given callback function `f`. 636 // If `f` returns true, then it continues iterating; or false to stop. 637 func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) { 638 a.mu.RLock() 639 defer a.mu.RUnlock() 640 for i := len(a.array) - 1; i >= 0; i-- { 641 if !f(i, a.array[i]) { 642 break 643 } 644 } 645 } 646 647 // String returns current array as a string, which implements like json.Marshal does. 648 func (a *SortedIntArray) String() string { 649 return "[" + a.Join(",") + "]" 650 } 651 652 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 653 // Note that do not use pointer as its receiver here. 654 func (a SortedIntArray) MarshalJSON() ([]byte, error) { 655 a.mu.RLock() 656 defer a.mu.RUnlock() 657 return json.Marshal(a.array) 658 } 659 660 // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. 661 func (a *SortedIntArray) UnmarshalJSON(b []byte) error { 662 if a.comparator == nil { 663 a.array = make([]int, 0) 664 a.comparator = defaultComparatorInt 665 } 666 a.mu.Lock() 667 defer a.mu.Unlock() 668 if err := json.UnmarshalUseNumber(b, &a.array); err != nil { 669 return err 670 } 671 if a.array != nil { 672 sort.Ints(a.array) 673 } 674 return nil 675 } 676 677 // UnmarshalValue is an interface implement which sets any type of value for array. 678 func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) { 679 if a.comparator == nil { 680 a.comparator = defaultComparatorInt 681 } 682 a.mu.Lock() 683 defer a.mu.Unlock() 684 switch value.(type) { 685 case string, []byte: 686 err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array) 687 default: 688 a.array = gconv.SliceInt(value) 689 } 690 if a.array != nil { 691 sort.Ints(a.array) 692 } 693 return err 694 } 695 696 // FilterEmpty removes all zero value of the array. 697 func (a *SortedIntArray) FilterEmpty() *SortedIntArray { 698 a.mu.Lock() 699 defer a.mu.Unlock() 700 for i := 0; i < len(a.array); { 701 if a.array[i] == 0 { 702 a.array = append(a.array[:i], a.array[i+1:]...) 703 } else { 704 break 705 } 706 } 707 for i := len(a.array) - 1; i >= 0; { 708 if a.array[i] == 0 { 709 a.array = append(a.array[:i], a.array[i+1:]...) 710 } else { 711 break 712 } 713 } 714 return a 715 } 716 717 // Walk applies a user supplied function `f` to every item of array. 718 func (a *SortedIntArray) Walk(f func(value int) int) *SortedIntArray { 719 a.mu.Lock() 720 defer a.mu.Unlock() 721 722 // Keep the array always sorted. 723 defer quickSortInt(a.array, a.getComparator()) 724 725 for i, v := range a.array { 726 a.array[i] = f(v) 727 } 728 return a 729 } 730 731 // IsEmpty checks whether the array is empty. 732 func (a *SortedIntArray) IsEmpty() bool { 733 return a.Len() == 0 734 } 735 736 // getComparator returns the comparator if it's previously set, 737 // or else it returns a default comparator. 738 func (a *SortedIntArray) getComparator() func(a, b int) int { 739 if a.comparator == nil { 740 return defaultComparatorInt 741 } 742 return a.comparator 743 }