github.com/zhongdalu/gf@v1.0.0/g/container/garray/garray_sorted_string.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf. 6 7 package garray 8 9 import ( 10 "bytes" 11 "encoding/json" 12 "math" 13 "sort" 14 "strings" 15 16 "github.com/zhongdalu/gf/g/container/gtype" 17 "github.com/zhongdalu/gf/g/internal/rwmutex" 18 "github.com/zhongdalu/gf/g/util/gconv" 19 "github.com/zhongdalu/gf/g/util/grand" 20 ) 21 22 // It's using increasing order in default. 23 type SortedStringArray struct { 24 mu *rwmutex.RWMutex 25 array []string 26 unique *gtype.Bool // Whether enable unique feature(false) 27 comparator func(v1, v2 string) int // Comparison function(it returns -1: v1 < v2; 0: v1 == v2; 1: v1 > v2) 28 } 29 30 // NewSortedStringArray creates and returns an empty sorted array. 31 // The parameter <unsafe> used to specify whether using array in un-concurrent-safety, 32 // which is false in default. 33 func NewSortedStringArray(unsafe ...bool) *SortedStringArray { 34 return NewSortedStringArraySize(0, unsafe...) 35 } 36 37 // NewSortedStringArraySize create and returns an sorted array with given size and cap. 38 // The parameter <unsafe> used to specify whether using array in un-concurrent-safety, 39 // which is false in default. 40 func NewSortedStringArraySize(cap int, unsafe ...bool) *SortedStringArray { 41 return &SortedStringArray{ 42 mu: rwmutex.New(unsafe...), 43 array: make([]string, 0, cap), 44 unique: gtype.NewBool(), 45 comparator: func(v1, v2 string) int { 46 return strings.Compare(v1, v2) 47 }, 48 } 49 } 50 51 // NewSortedStringArrayFrom creates and returns an sorted array with given slice <array>. 52 // The parameter <unsafe> used to specify whether using array in un-concurrent-safety, 53 // which is false in default. 54 func NewSortedStringArrayFrom(array []string, unsafe ...bool) *SortedStringArray { 55 a := NewSortedStringArraySize(0, unsafe...) 56 a.array = array 57 sort.Strings(a.array) 58 return a 59 } 60 61 // NewSortedStringArrayFromCopy creates and returns an sorted array from a copy of given slice <array>. 62 // The parameter <unsafe> used to specify whether using array in un-concurrent-safety, 63 // which is false in default. 64 func NewSortedStringArrayFromCopy(array []string, unsafe ...bool) *SortedStringArray { 65 newArray := make([]string, len(array)) 66 copy(newArray, array) 67 return NewSortedStringArrayFrom(newArray, unsafe...) 68 } 69 70 // SetArray sets the underlying slice array with the given <array>. 71 func (a *SortedStringArray) SetArray(array []string) *SortedStringArray { 72 a.mu.Lock() 73 defer a.mu.Unlock() 74 a.array = array 75 sort.Strings(a.array) 76 return a 77 } 78 79 // Sort sorts the array in increasing order. 80 // The parameter <reverse> controls whether sort 81 // in increasing order(default) or decreasing order. 82 func (a *SortedStringArray) Sort() *SortedStringArray { 83 a.mu.Lock() 84 defer a.mu.Unlock() 85 sort.Strings(a.array) 86 return a 87 } 88 89 // Add adds one or multiple values to sorted array, the array always keeps sorted. 90 func (a *SortedStringArray) Add(values ...string) *SortedStringArray { 91 if len(values) == 0 { 92 return a 93 } 94 a.mu.Lock() 95 defer a.mu.Unlock() 96 for _, value := range values { 97 index, cmp := a.binSearch(value, false) 98 if a.unique.Val() && cmp == 0 { 99 continue 100 } 101 if index < 0 { 102 a.array = append(a.array, value) 103 continue 104 } 105 if cmp > 0 { 106 index++ 107 } 108 rear := append([]string{}, a.array[index:]...) 109 a.array = append(a.array[0:index], value) 110 a.array = append(a.array, rear...) 111 } 112 return a 113 } 114 115 // Get returns the value of the specified index, 116 // the caller should notice the boundary of the array. 117 func (a *SortedStringArray) Get(index int) string { 118 a.mu.RLock() 119 defer a.mu.RUnlock() 120 value := a.array[index] 121 return value 122 } 123 124 // Remove removes an item by index. 125 func (a *SortedStringArray) Remove(index int) string { 126 a.mu.Lock() 127 defer a.mu.Unlock() 128 // Determine array boundaries when deleting to improve deletion efficiency. 129 if index == 0 { 130 value := a.array[0] 131 a.array = a.array[1:] 132 return value 133 } else if index == len(a.array)-1 { 134 value := a.array[index] 135 a.array = a.array[:index] 136 return value 137 } 138 // If it is a non-boundary delete, 139 // it will involve the creation of an array, 140 // then the deletion is less efficient. 141 value := a.array[index] 142 a.array = append(a.array[:index], a.array[index+1:]...) 143 return value 144 } 145 146 // PopLeft pops and returns an item from the beginning of array. 147 func (a *SortedStringArray) PopLeft() string { 148 a.mu.Lock() 149 defer a.mu.Unlock() 150 value := a.array[0] 151 a.array = a.array[1:] 152 return value 153 } 154 155 // PopRight pops and returns an item from the end of array. 156 func (a *SortedStringArray) PopRight() string { 157 a.mu.Lock() 158 defer a.mu.Unlock() 159 index := len(a.array) - 1 160 value := a.array[index] 161 a.array = a.array[:index] 162 return value 163 } 164 165 // PopRand randomly pops and return an item out of array. 166 func (a *SortedStringArray) PopRand() string { 167 return a.Remove(grand.Intn(len(a.array))) 168 } 169 170 // PopRands randomly pops and returns <size> items out of array. 171 func (a *SortedStringArray) PopRands(size int) []string { 172 a.mu.Lock() 173 defer a.mu.Unlock() 174 if size > len(a.array) { 175 size = len(a.array) 176 } 177 array := make([]string, size) 178 for i := 0; i < size; i++ { 179 index := grand.Intn(len(a.array)) 180 array[i] = a.array[index] 181 a.array = append(a.array[:index], a.array[index+1:]...) 182 } 183 return array 184 } 185 186 // PopLefts pops and returns <size> items from the beginning of array. 187 func (a *SortedStringArray) PopLefts(size int) []string { 188 a.mu.Lock() 189 defer a.mu.Unlock() 190 length := len(a.array) 191 if size > length { 192 size = length 193 } 194 value := a.array[0:size] 195 a.array = a.array[size:] 196 return value 197 } 198 199 // PopRights pops and returns <size> items from the end of array. 200 func (a *SortedStringArray) PopRights(size int) []string { 201 a.mu.Lock() 202 defer a.mu.Unlock() 203 index := len(a.array) - size 204 if index < 0 { 205 index = 0 206 } 207 value := a.array[index:] 208 a.array = a.array[:index] 209 return value 210 } 211 212 // Range picks and returns items by range, like array[start:end]. 213 // Notice, if in concurrent-safe usage, it returns a copy of slice; 214 // else a pointer to the underlying data. 215 // 216 // If <end> is negative, then the offset will start from the end of array. 217 // If <end> is omitted, then the sequence will have everything from start up 218 // until the end of the array. 219 func (a *SortedStringArray) Range(start int, end ...int) []string { 220 a.mu.RLock() 221 defer a.mu.RUnlock() 222 offsetEnd := len(a.array) 223 if len(end) > 0 && end[0] < offsetEnd { 224 offsetEnd = end[0] 225 } 226 if start > offsetEnd { 227 return nil 228 } 229 if start < 0 { 230 start = 0 231 } 232 array := ([]string)(nil) 233 if a.mu.IsSafe() { 234 array = make([]string, offsetEnd-start) 235 copy(array, a.array[start:offsetEnd]) 236 } else { 237 array = a.array[start:offsetEnd] 238 } 239 return array 240 } 241 242 // SubSlice returns a slice of elements from the array as specified 243 // by the <offset> and <size> parameters. 244 // If in concurrent safe usage, it returns a copy of the slice; else a pointer. 245 // 246 // If offset is non-negative, the sequence will start at that offset in the array. 247 // If offset is negative, the sequence will start that far from the end of the array. 248 // 249 // If length is given and is positive, then the sequence will have up to that many elements in it. 250 // If the array is shorter than the length, then only the available array elements will be present. 251 // If length is given and is negative then the sequence will stop that many elements from the end of the array. 252 // If it is omitted, then the sequence will have everything from offset up until the end of the array. 253 // 254 // Any possibility crossing the left border of array, it will fail. 255 func (a *SortedStringArray) SubSlice(offset int, length ...int) []string { 256 a.mu.RLock() 257 defer a.mu.RUnlock() 258 size := len(a.array) 259 if len(length) > 0 { 260 size = length[0] 261 } 262 if offset > len(a.array) { 263 return nil 264 } 265 if offset < 0 { 266 offset = len(a.array) + offset 267 if offset < 0 { 268 return nil 269 } 270 } 271 if size < 0 { 272 offset += size 273 size = -size 274 if offset < 0 { 275 return nil 276 } 277 } 278 end := offset + size 279 if end > len(a.array) { 280 end = len(a.array) 281 size = len(a.array) - offset 282 } 283 if a.mu.IsSafe() { 284 s := make([]string, size) 285 copy(s, a.array[offset:]) 286 return s 287 } else { 288 return a.array[offset:end] 289 } 290 } 291 292 // Sum returns the sum of values in an array. 293 func (a *SortedStringArray) Sum() (sum int) { 294 a.mu.RLock() 295 defer a.mu.RUnlock() 296 for _, v := range a.array { 297 sum += gconv.Int(v) 298 } 299 return 300 } 301 302 // Len returns the length of array. 303 func (a *SortedStringArray) Len() int { 304 a.mu.RLock() 305 length := len(a.array) 306 a.mu.RUnlock() 307 return length 308 } 309 310 // Slice returns the underlying data of array. 311 // Notice, if in concurrent-safe usage, it returns a copy of slice; 312 // else a pointer to the underlying data. 313 func (a *SortedStringArray) Slice() []string { 314 array := ([]string)(nil) 315 if a.mu.IsSafe() { 316 a.mu.RLock() 317 defer a.mu.RUnlock() 318 array = make([]string, len(a.array)) 319 copy(array, a.array) 320 } else { 321 array = a.array 322 } 323 return array 324 } 325 326 // Contains checks whether a value exists in the array. 327 func (a *SortedStringArray) Contains(value string) bool { 328 return a.Search(value) != -1 329 } 330 331 // Search searches array by <value>, returns the index of <value>, 332 // or returns -1 if not exists. 333 func (a *SortedStringArray) Search(value string) (index int) { 334 if i, r := a.binSearch(value, true); r == 0 { 335 return i 336 } 337 return -1 338 } 339 340 // Binary search. 341 // It returns the last compared index and the result. 342 // If <result> equals to 0, it means the value at <index> is equals to <value>. 343 // If <result> lesser than 0, it means the value at <index> is lesser than <value>. 344 // If <result> greater than 0, it means the value at <index> is greater than <value>. 345 func (a *SortedStringArray) binSearch(value string, lock bool) (index int, result int) { 346 if len(a.array) == 0 { 347 return -1, -2 348 } 349 if lock { 350 a.mu.RLock() 351 defer a.mu.RUnlock() 352 } 353 min := 0 354 max := len(a.array) - 1 355 mid := 0 356 cmp := -2 357 for min <= max { 358 mid = int((min + max) / 2) 359 cmp = a.comparator(value, a.array[mid]) 360 switch { 361 case cmp < 0: 362 max = mid - 1 363 case cmp > 0: 364 min = mid + 1 365 default: 366 return mid, cmp 367 } 368 } 369 return mid, cmp 370 } 371 372 // SetUnique sets unique mark to the array, 373 // which means it does not contain any repeated items. 374 // It also do unique check, remove all repeated items. 375 func (a *SortedStringArray) SetUnique(unique bool) *SortedStringArray { 376 oldUnique := a.unique.Val() 377 a.unique.Set(unique) 378 if unique && oldUnique != unique { 379 a.Unique() 380 } 381 return a 382 } 383 384 // Unique uniques the array, clear repeated items. 385 func (a *SortedStringArray) Unique() *SortedStringArray { 386 a.mu.Lock() 387 i := 0 388 for { 389 if i == len(a.array)-1 { 390 break 391 } 392 if a.comparator(a.array[i], a.array[i+1]) == 0 { 393 a.array = append(a.array[:i+1], a.array[i+1+1:]...) 394 } else { 395 i++ 396 } 397 } 398 a.mu.Unlock() 399 return a 400 } 401 402 // Clone returns a new array, which is a copy of current array. 403 func (a *SortedStringArray) Clone() (newArray *SortedStringArray) { 404 a.mu.RLock() 405 array := make([]string, len(a.array)) 406 copy(array, a.array) 407 a.mu.RUnlock() 408 return NewSortedStringArrayFrom(array, !a.mu.IsSafe()) 409 } 410 411 // Clear deletes all items of current array. 412 func (a *SortedStringArray) Clear() *SortedStringArray { 413 a.mu.Lock() 414 if len(a.array) > 0 { 415 a.array = make([]string, 0) 416 } 417 a.mu.Unlock() 418 return a 419 } 420 421 // LockFunc locks writing by callback function <f>. 422 func (a *SortedStringArray) LockFunc(f func(array []string)) *SortedStringArray { 423 a.mu.Lock() 424 defer a.mu.Unlock() 425 f(a.array) 426 return a 427 } 428 429 // RLockFunc locks reading by callback function <f>. 430 func (a *SortedStringArray) RLockFunc(f func(array []string)) *SortedStringArray { 431 a.mu.RLock() 432 defer a.mu.RUnlock() 433 f(a.array) 434 return a 435 } 436 437 // Merge merges <array> into current array. 438 // The parameter <array> can be any garray or slice type. 439 // The difference between Merge and Append is Append supports only specified slice type, 440 // but Merge supports more parameter types. 441 func (a *SortedStringArray) Merge(array interface{}) *SortedStringArray { 442 switch v := array.(type) { 443 case *Array: 444 a.Add(gconv.Strings(v.Slice())...) 445 case *IntArray: 446 a.Add(gconv.Strings(v.Slice())...) 447 case *StringArray: 448 a.Add(gconv.Strings(v.Slice())...) 449 case *SortedArray: 450 a.Add(gconv.Strings(v.Slice())...) 451 case *SortedIntArray: 452 a.Add(gconv.Strings(v.Slice())...) 453 case *SortedStringArray: 454 a.Add(gconv.Strings(v.Slice())...) 455 default: 456 a.Add(gconv.Strings(array)...) 457 } 458 return a 459 } 460 461 // Chunk splits an array into multiple arrays, 462 // the size of each array is determined by <size>. 463 // The last chunk may contain less than size elements. 464 func (a *SortedStringArray) Chunk(size int) [][]string { 465 if size < 1 { 466 return nil 467 } 468 a.mu.RLock() 469 defer a.mu.RUnlock() 470 length := len(a.array) 471 chunks := int(math.Ceil(float64(length) / float64(size))) 472 var n [][]string 473 for i, end := 0, 0; chunks > 0; chunks-- { 474 end = (i + 1) * size 475 if end > length { 476 end = length 477 } 478 n = append(n, a.array[i*size:end]) 479 i++ 480 } 481 return n 482 } 483 484 // Rand randomly returns one item from array(no deleting). 485 func (a *SortedStringArray) Rand() string { 486 a.mu.RLock() 487 defer a.mu.RUnlock() 488 return a.array[grand.Intn(len(a.array))] 489 } 490 491 // Rands randomly returns <size> items from array(no deleting). 492 func (a *SortedStringArray) Rands(size int) []string { 493 a.mu.RLock() 494 defer a.mu.RUnlock() 495 if size > len(a.array) { 496 size = len(a.array) 497 } 498 n := make([]string, size) 499 for i, v := range grand.Perm(len(a.array)) { 500 n[i] = a.array[v] 501 if i == size-1 { 502 break 503 } 504 } 505 return n 506 } 507 508 // Join joins array elements with a string <glue>. 509 func (a *SortedStringArray) Join(glue string) string { 510 a.mu.RLock() 511 defer a.mu.RUnlock() 512 buffer := bytes.NewBuffer(nil) 513 for k, v := range a.array { 514 buffer.WriteString(gconv.String(v)) 515 if k != len(a.array)-1 { 516 buffer.WriteString(glue) 517 } 518 } 519 return buffer.String() 520 } 521 522 // CountValues counts the number of occurrences of all values in the array. 523 func (a *SortedStringArray) CountValues() map[string]int { 524 m := make(map[string]int) 525 a.mu.RLock() 526 defer a.mu.RUnlock() 527 for _, v := range a.array { 528 m[v]++ 529 } 530 return m 531 } 532 533 // String returns current array as a string. 534 func (a *SortedStringArray) String() string { 535 a.mu.RLock() 536 defer a.mu.RUnlock() 537 jsonContent, _ := json.Marshal(a.array) 538 return string(jsonContent) 539 } 540 541 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 542 func (a *SortedStringArray) MarshalJSON() ([]byte, error) { 543 a.mu.RLock() 544 defer a.mu.RUnlock() 545 return json.Marshal(a.array) 546 }