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