github.com/andeya/ameda@v1.5.3/strings.go (about) 1 package ameda 2 3 import ( 4 "strings" 5 ) 6 7 // OneString try to return the first element, otherwise return zero value. 8 func OneString(s []string) string { 9 if len(s) > 0 { 10 return s[0] 11 } 12 return "" 13 } 14 15 // StringsCopy creates a copy of the string slice. 16 func StringsCopy(s []string) []string { 17 b := make([]string, len(s)) 18 copy(b, s) 19 return b 20 } 21 22 // StringsToInterfaces converts string slice to interface slice. 23 func StringsToInterfaces(s []string) []interface{} { 24 r := make([]interface{}, len(s)) 25 for k, v := range s { 26 r[k] = StringToInterface(v) 27 } 28 return r 29 } 30 31 // StringsToBools converts string slice to bool slice. 32 func StringsToBools(s []string, emptyAsZero ...bool) ([]bool, error) { 33 var err error 34 r := make([]bool, len(s)) 35 for k, v := range s { 36 r[k], err = StringToBool(v, emptyAsZero...) 37 if err != nil { 38 return r, err 39 } 40 } 41 return r, nil 42 } 43 44 // StringsToFloat32s converts string slice to float32 slice. 45 func StringsToFloat32s(s []string, emptyAsZero ...bool) ([]float32, error) { 46 var err error 47 r := make([]float32, len(s)) 48 for k, v := range s { 49 r[k], err = StringToFloat32(v, emptyAsZero...) 50 if err != nil { 51 return r, err 52 } 53 } 54 return r, nil 55 } 56 57 // StringsToFloat64s converts string slice to float64 slice. 58 func StringsToFloat64s(s []string, emptyAsZero ...bool) ([]float64, error) { 59 var err error 60 r := make([]float64, len(s)) 61 for k, v := range s { 62 r[k], err = StringToFloat64(v, emptyAsZero...) 63 if err != nil { 64 return r, err 65 } 66 } 67 return r, nil 68 } 69 70 // StringsToInts converts string slice to int slice. 71 func StringsToInts(s []string, emptyAsZero ...bool) ([]int, error) { 72 var err error 73 r := make([]int, len(s)) 74 for k, v := range s { 75 r[k], err = StringToInt(v, emptyAsZero...) 76 if err != nil { 77 return r, err 78 } 79 } 80 return r, nil 81 } 82 83 // StringsToInt8s converts string slice to int8 slice. 84 func StringsToInt8s(s []string, emptyAsZero ...bool) ([]int8, error) { 85 var err error 86 r := make([]int8, len(s)) 87 for k, v := range s { 88 r[k], err = StringToInt8(v, emptyAsZero...) 89 if err != nil { 90 return r, err 91 } 92 } 93 return r, nil 94 } 95 96 // StringsToInt16s converts string slice to int16 slice. 97 func StringsToInt16s(s []string, emptyAsZero ...bool) ([]int16, error) { 98 var err error 99 r := make([]int16, len(s)) 100 for k, v := range s { 101 r[k], err = StringToInt16(v, emptyAsZero...) 102 if err != nil { 103 return r, err 104 } 105 } 106 return r, nil 107 } 108 109 // StringsToInt32s converts string slice to int32 slice. 110 func StringsToInt32s(s []string, emptyAsZero ...bool) ([]int32, error) { 111 var err error 112 r := make([]int32, len(s)) 113 for k, v := range s { 114 r[k], err = StringToInt32(v, emptyAsZero...) 115 if err != nil { 116 return r, err 117 } 118 } 119 return r, nil 120 } 121 122 // StringsToInt64s converts string slice to int64 slice. 123 func StringsToInt64s(s []string, emptyAsZero ...bool) ([]int64, error) { 124 var err error 125 r := make([]int64, len(s)) 126 for k, v := range s { 127 r[k], err = StringToInt64(v, emptyAsZero...) 128 if err != nil { 129 return r, err 130 } 131 } 132 return r, nil 133 } 134 135 // StringsToUints converts string slice to uint slice. 136 func StringsToUints(s []string, emptyAsZero ...bool) ([]uint, error) { 137 var err error 138 r := make([]uint, len(s)) 139 for k, v := range s { 140 r[k], err = StringToUint(v, emptyAsZero...) 141 if err != nil { 142 return r, err 143 } 144 } 145 return r, nil 146 } 147 148 // StringsToUint8s converts string slice to uint8 slice. 149 func StringsToUint8s(s []string, emptyAsZero ...bool) ([]uint8, error) { 150 var err error 151 r := make([]uint8, len(s)) 152 for k, v := range s { 153 r[k], err = StringToUint8(v, emptyAsZero...) 154 if err != nil { 155 return r, err 156 } 157 } 158 return r, nil 159 } 160 161 // StringsToUint16s converts string slice to uint16 slice. 162 func StringsToUint16s(s []string, emptyAsZero ...bool) ([]uint16, error) { 163 var err error 164 r := make([]uint16, len(s)) 165 for k, v := range s { 166 r[k], err = StringToUint16(v, emptyAsZero...) 167 if err != nil { 168 return r, err 169 } 170 } 171 return r, nil 172 } 173 174 // StringsToUint32s converts string slice to uint32 slice. 175 func StringsToUint32s(s []string, emptyAsZero ...bool) ([]uint32, error) { 176 var err error 177 r := make([]uint32, len(s)) 178 for k, v := range s { 179 r[k], err = StringToUint32(v, emptyAsZero...) 180 if err != nil { 181 return r, err 182 } 183 } 184 return r, nil 185 } 186 187 // StringsToUint64s converts string slice to uint64 slice. 188 func StringsToUint64s(s []string, emptyAsZero ...bool) ([]uint64, error) { 189 var err error 190 r := make([]uint64, len(s)) 191 for k, v := range s { 192 r[k], err = StringToUint64(v, emptyAsZero...) 193 if err != nil { 194 return r, err 195 } 196 } 197 return r, nil 198 } 199 200 // StringsCopyWithin copies part of an slice to another location in the current slice. 201 // @target 202 // 203 // Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. 204 // 205 // @start 206 // 207 // Zero-based index at which to start copying elements from. If negative, start will be counted from the end. 208 // 209 // @end 210 // 211 // Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. 212 // If negative, end will be counted from the end. 213 // If end is omitted, CopyWithin will copy until the last index (default to len(s)). 214 func StringsCopyWithin(s []string, target, start int, end ...int) { 215 target = fixIndex(len(s), target, true) 216 if target == len(s) { 217 return 218 } 219 sub := StringsSlice(s, start, end...) 220 for i, v := range sub { 221 s[target+i] = v 222 } 223 } 224 225 // StringsEvery tests whether all elements in the slice pass the test implemented by the provided function. 226 // NOTE: 227 // 228 // Calling this method on an empty slice will return true for any condition! 229 func StringsEvery(s []string, fn func(s []string, k int, v string) bool) bool { 230 for k, v := range s { 231 if !fn(s, k, v) { 232 return false 233 } 234 } 235 return true 236 } 237 238 // StringsFill changes all elements in the current slice to a value, from a start index to an end index. 239 // @value 240 // 241 // Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. 242 // 243 // @start 244 // 245 // Zero-based index at which to start copying elements from. If negative, start will be counted from the end. 246 // 247 // @end 248 // 249 // Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. 250 // If negative, end will be counted from the end. 251 // If end is omitted, CopyWithin will copy until the last index (default to len(s)). 252 func StringsFill(s []string, value string, start int, end ...int) { 253 fixedStart, fixedEnd, ok := fixRange(len(s), start, end...) 254 if !ok { 255 return 256 } 257 for i := fixedStart; i < fixedEnd; i++ { 258 s[i] = value 259 } 260 } 261 262 // StringsFilter creates a new slice with all elements that pass the test implemented by the provided function. 263 func StringsFilter(s []string, fn func(s []string, k int, v string) bool) []string { 264 ret := make([]string, 0) 265 for k, v := range s { 266 if fn(s, k, v) { 267 ret = append(ret, v) 268 } 269 } 270 return ret 271 } 272 273 // StringsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. 274 // NOTE: 275 // 276 // If not found, k = -1 277 func StringsFind(s []string, fn func(s []string, k int, v string) bool) (k int, v string) { 278 for k, v := range s { 279 if fn(s, k, v) { 280 return k, v 281 } 282 } 283 return -1, "" 284 } 285 286 // StringsIncludes determines whether an slice includes a certain value among its entries. 287 // @fromIndex 288 // 289 // The index to start the search at. Defaults to 0. 290 func StringsIncludes(s []string, valueToFind string, fromIndex ...int) bool { 291 return StringsIndexOf(s, valueToFind, fromIndex...) > -1 292 } 293 294 // StringsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. 295 // @fromIndex 296 // 297 // The index to start the search at. Defaults to 0. 298 func StringsIndexOf(s []string, searchElement string, fromIndex ...int) int { 299 idx := getFromIndex(len(s), fromIndex...) 300 for k, v := range s[idx:] { 301 if searchElement == v { 302 return k + idx 303 } 304 } 305 return -1 306 } 307 308 // StringsJoin concatenates the elements of s to create a single string. The separator string 309 // sep is placed between elements in the resulting string. 310 func StringsJoin(s []string, sep string) string { 311 return strings.Join(s, sep) 312 } 313 314 // StringsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. 315 // @fromIndex 316 // 317 // The index to start the search at. Defaults to 0. 318 func StringsLastIndexOf(s []string, searchElement string, fromIndex ...int) int { 319 idx := getFromIndex(len(s), fromIndex...) 320 for i := len(s) - 1; i >= idx; i-- { 321 if searchElement == s[i] { 322 return i 323 } 324 } 325 return -1 326 } 327 328 // StringsMap creates a new slice populated with the results of calling a provided function 329 // on every element in the calling slice. 330 func StringsMap(s []string, fn func(s []string, k int, v string) string) []string { 331 ret := make([]string, len(s)) 332 for k, v := range s { 333 ret[k] = fn(s, k, v) 334 } 335 return ret 336 } 337 338 // StringsPop removes the last element from an slice and returns that element. 339 // This method changes the length of the slice. 340 func StringsPop(s *[]string) (string, bool) { 341 a := *s 342 if len(a) == 0 { 343 return "", false 344 } 345 lastIndex := len(a) - 1 346 last := a[lastIndex] 347 a = a[:lastIndex] 348 *s = a[:len(a):len(a)] 349 return last, true 350 } 351 352 // StringsPush adds one or more elements to the end of an slice and returns the new length of the slice. 353 func StringsPush(s *[]string, element ...string) int { 354 *s = append(*s, element...) 355 return len(*s) 356 } 357 358 // StringsPushDistinct adds one or more new elements that do not exist in the current slice at the end. 359 func StringsPushDistinct(s []string, element ...string) []string { 360 L: 361 for _, v := range element { 362 for _, vv := range s { 363 if vv == v { 364 continue L 365 } 366 } 367 s = append(s, v) 368 } 369 return s 370 } 371 372 // StringsReduce executes a reducer function (that you provide) on each element of the slice, 373 // resulting in a single output value. 374 // @accumulator 375 // 376 // The accumulator accumulates callback's return values. 377 // It is the accumulated value previously returned in the last invocation of the callback—or initialValue, 378 // if it was supplied (see below). 379 // 380 // @initialValue 381 // 382 // A value to use as the first argument to the first call of the callback. 383 // If no initialValue is supplied, the first element in the slice will be used and skipped. 384 func StringsReduce(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { 385 if len(s) == 0 { 386 return "" 387 } 388 start := 0 389 acc := s[start] 390 if len(initialValue) > 0 { 391 acc = initialValue[0] 392 } else { 393 start += 1 394 } 395 for i := start; i < len(s); i++ { 396 acc = fn(s, i, s[i], acc) 397 } 398 return acc 399 } 400 401 // StringsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) 402 // to reduce it to a single value. 403 // @accumulator 404 // 405 // The accumulator accumulates callback's return values. 406 // It is the accumulated value previously returned in the last invocation of the callback—or initialValue, 407 // if it was supplied (see below). 408 // 409 // @initialValue 410 // 411 // A value to use as the first argument to the first call of the callback. 412 // If no initialValue is supplied, the first element in the slice will be used and skipped. 413 func StringsReduceRight(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { 414 if len(s) == 0 { 415 return "" 416 } 417 end := len(s) - 1 418 acc := s[end] 419 if len(initialValue) > 0 { 420 acc = initialValue[0] 421 } else { 422 end -= 1 423 } 424 for i := end; i >= 0; i-- { 425 acc = fn(s, i, s[i], acc) 426 } 427 return acc 428 } 429 430 // StringsReverse reverses an slice in place. 431 func StringsReverse(s []string) { 432 first := 0 433 last := len(s) - 1 434 for first < last { 435 s[first], s[last] = s[last], s[first] 436 first++ 437 last-- 438 } 439 } 440 441 // StringsShift removes the first element from an slice and returns that removed element. 442 // This method changes the length of the slice. 443 func StringsShift(s *[]string) (string, bool) { 444 a := *s 445 if len(a) == 0 { 446 return "", false 447 } 448 first := a[0] 449 a = a[1:] 450 *s = a[:len(a):len(a)] 451 return first, true 452 } 453 454 // StringsSlice returns a copy of a portion of an slice into a new slice object selected 455 // from begin to end (end not included) where begin and end represent the index of items in that slice. 456 // The original slice will not be modified. 457 func StringsSlice(s []string, begin int, end ...int) []string { 458 fixedStart, fixedEnd, ok := fixRange(len(s), begin, end...) 459 if !ok { 460 return []string{} 461 } 462 return StringsCopy(s[fixedStart:fixedEnd]) 463 } 464 465 // StringsSome tests whether at least one element in the slice passes the test implemented by the provided function. 466 // NOTE: 467 // 468 // Calling this method on an empty slice returns false for any condition! 469 func StringsSome(s []string, fn func(s []string, k int, v string) bool) bool { 470 for k, v := range s { 471 if fn(s, k, v) { 472 return true 473 } 474 } 475 return false 476 } 477 478 // StringsSplice changes the contents of an slice by removing or replacing 479 // existing elements and/or adding new elements in place. 480 func StringsSplice(s *[]string, start, deleteCount int, items ...string) { 481 a := *s 482 if deleteCount < 0 { 483 deleteCount = 0 484 } 485 start, end, _ := fixRange(len(a), start, start+1+deleteCount) 486 deleteCount = end - start - 1 487 for i := 0; i < len(items); i++ { 488 if deleteCount > 0 { 489 // replace 490 a[start] = items[i] 491 deleteCount-- 492 start++ 493 } else { 494 // insert 495 lastSlice := StringsCopy(a[start:]) 496 items = items[i:] 497 a = append(a[:start], items...) 498 a = append(a[:start+len(items)], lastSlice...) 499 *s = a[:len(a):len(a)] 500 return 501 } 502 } 503 if deleteCount > 0 { 504 a = append(a[:start], a[start+1+deleteCount:]...) 505 } 506 *s = a[:len(a):len(a)] 507 } 508 509 // StringsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. 510 func StringsUnshift(s *[]string, element ...string) int { 511 *s = append(element, *s...) 512 return len(*s) 513 } 514 515 // StringsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning 516 // and returns the new length of the slice. 517 func StringsUnshiftDistinct(s *[]string, element ...string) int { 518 a := *s 519 if len(element) == 0 { 520 return len(a) 521 } 522 m := make(map[string]bool, len(element)) 523 r := make([]string, 0, len(a)+len(element)) 524 L: 525 for _, v := range element { 526 if m[v] { 527 continue 528 } 529 m[v] = true 530 for _, vv := range a { 531 if vv == v { 532 continue L 533 } 534 } 535 r = append(r, v) 536 } 537 r = append(r, a...) 538 *s = r[:len(r):len(r)] 539 return len(r) 540 } 541 542 // StringsRemoveFirst removes the first matched elements from the slice, 543 // and returns the new length of the slice. 544 func StringsRemoveFirst(p *[]string, elements ...string) int { 545 a := *p 546 m := make(map[interface{}]struct{}, len(elements)) 547 for _, element := range elements { 548 if _, ok := m[element]; ok { 549 continue 550 } 551 m[element] = struct{}{} 552 for k, v := range a { 553 if v == element { 554 a = append(a[:k], a[k+1:]...) 555 break 556 } 557 } 558 } 559 n := len(a) 560 *p = a[:n:n] 561 return n 562 } 563 564 // StringsRemoveEvery removes all the elements from the slice, 565 // and returns the new length of the slice. 566 func StringsRemoveEvery(p *[]string, elements ...string) int { 567 a := *p 568 m := make(map[interface{}]struct{}, len(elements)) 569 for _, element := range elements { 570 if _, ok := m[element]; ok { 571 continue 572 } 573 m[element] = struct{}{} 574 for i := 0; i < len(a); i++ { 575 if a[i] == element { 576 a = append(a[:i], a[i+1:]...) 577 i-- 578 } 579 } 580 } 581 n := len(a) 582 *p = a[:n:n] 583 return n 584 } 585 586 // StringsConcat is used to merge two or more slices. 587 // This method does not change the existing slices, but instead returns a new slice. 588 func StringsConcat(s ...[]string) []string { 589 var totalLen int 590 for _, v := range s { 591 totalLen += len(v) 592 } 593 ret := make([]string, totalLen) 594 dst := ret 595 for _, v := range s { 596 n := copy(dst, v) 597 dst = dst[n:] 598 } 599 return ret 600 } 601 602 // StringsIntersect calculates intersection of two or more slices, 603 // and returns the count of each element. 604 func StringsIntersect(s ...[]string) (intersectCount map[string]int) { 605 if len(s) == 0 { 606 return nil 607 } 608 for _, v := range s { 609 if len(v) == 0 { 610 return nil 611 } 612 } 613 counts := make([]map[string]int, len(s)) 614 for k, v := range s { 615 counts[k] = stringsDistinct(v, nil) 616 } 617 intersectCount = counts[0] 618 L: 619 for k, v := range intersectCount { 620 for _, c := range counts[1:] { 621 v2 := c[k] 622 if v2 == 0 { 623 delete(intersectCount, k) 624 continue L 625 } 626 if v > v2 { 627 v = v2 628 } 629 } 630 intersectCount[k] = v 631 } 632 return intersectCount 633 } 634 635 // StringsDistinct calculates the count of each different element, 636 // and only saves these different elements in place if changeSlice is true. 637 func StringsDistinct(s *[]string, changeSlice bool) (distinctCount map[string]int) { 638 if !changeSlice { 639 return stringsDistinct(*s, nil) 640 } 641 a := (*s)[:0] 642 distinctCount = stringsDistinct(*s, &a) 643 n := len(distinctCount) 644 *s = a[:n:n] 645 return distinctCount 646 } 647 648 func stringsDistinct(src []string, dst *[]string) map[string]int { 649 m := make(map[string]int, len(src)) 650 if dst == nil { 651 for _, v := range src { 652 n := m[v] 653 m[v] = n + 1 654 } 655 } else { 656 a := *dst 657 for _, v := range src { 658 n := m[v] 659 m[v] = n + 1 660 if n == 0 { 661 a = append(a, v) 662 } 663 } 664 *dst = a 665 } 666 return m 667 } 668 669 // StringSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... 670 // This method does not change the existing slices, but instead returns a new slice. 671 func StringSetUnion(set1, set2 []string, others ...[]string) []string { 672 m := make(map[string]struct{}, len(set1)+len(set2)) 673 r := make([]string, 0, len(m)) 674 for _, set := range append([][]string{set1, set2}, others...) { 675 for _, v := range set { 676 _, ok := m[v] 677 if ok { 678 continue 679 } 680 r = append(r, v) 681 m[v] = struct{}{} 682 } 683 } 684 return r 685 } 686 687 // StringSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... 688 // This method does not change the existing slices, but instead returns a new slice. 689 func StringSetIntersect(set1, set2 []string, others ...[]string) []string { 690 sets := append([][]string{set2}, others...) 691 setsCount := make([]map[string]int, len(sets)) 692 for k, v := range sets { 693 setsCount[k] = stringsDistinct(v, nil) 694 } 695 m := make(map[string]struct{}, len(set1)) 696 r := make([]string, 0, len(m)) 697 L: 698 for _, v := range set1 { 699 if _, ok := m[v]; ok { 700 continue 701 } 702 m[v] = struct{}{} 703 for _, m2 := range setsCount { 704 if m2[v] == 0 { 705 continue L 706 } 707 } 708 r = append(r, v) 709 } 710 return r 711 } 712 713 // StringSetDifference calculates between multiple collections: set1 - set2 - others... 714 // This method does not change the existing slices, but instead returns a new slice. 715 func StringSetDifference(set1, set2 []string, others ...[]string) []string { 716 m := make(map[string]struct{}, len(set1)) 717 r := make([]string, 0, len(set1)) 718 sets := append([][]string{set2}, others...) 719 for _, v := range sets { 720 inter := StringSetIntersect(set1, v) 721 for _, v := range inter { 722 m[v] = struct{}{} 723 } 724 } 725 for _, v := range set1 { 726 if _, ok := m[v]; !ok { 727 r = append(r, v) 728 m[v] = struct{}{} 729 } 730 } 731 return r 732 }