github.com/seeker-insurance/kit@v0.0.13/stringslice/stringslice.go (about)

     1  //Package stringslice contains various functions to work with slices of strings and the strings contained within.
     2  package stringslice
     3  
     4  import "sort"
     5  
     6  type predicate func(string) bool
     7  
     8  //IndexOf returns the index of the search string
     9  func IndexOf(a []string, search string) (int, bool) {
    10  	for i, s := range a {
    11  		if s == search {
    12  			return i, true
    13  		}
    14  	}
    15  	return 0, false
    16  }
    17  
    18  //NonEmpty returns a slice containing the non-empty elements of a
    19  func NonEmpty(a []string) []string {
    20  	var filtered []string
    21  	return AppendIfNonEmpty(filtered, a...)
    22  }
    23  
    24  //All returns true if f(s) is true for all s in a. All([], f) is true.
    25  func All(a []string, f predicate) bool {
    26  	for _, s := range a {
    27  		if !f(s) {
    28  			return false
    29  		}
    30  	}
    31  	return true
    32  }
    33  
    34  //Copy makes a copy of the []string.
    35  func Copy(src []string) []string {
    36  	dst := make([]string, len(src))
    37  	copy(dst, src)
    38  	return dst
    39  }
    40  
    41  //Any (returns true if f(s) is true for any s in a. Any([], f) is false.
    42  func Any(a []string, f func(string) bool) bool {
    43  	for _, s := range a {
    44  		if f(s) {
    45  			return true
    46  		}
    47  	}
    48  	return false
    49  }
    50  
    51  //Filter returns the elements of a where f(a) is true.
    52  func Filter(a []string, f func(string) bool) []string {
    53  	filtered := make([]string, 0, len(a))
    54  	for _, s := range a {
    55  		if f(s) {
    56  			filtered = append(filtered, s)
    57  		}
    58  	}
    59  	return filtered
    60  }
    61  
    62  //FilterFalse returns the elements of a where f(a) is false.
    63  func FilterFalse(a []string, f func(string) bool) []string {
    64  	filtered := make([]string, 0, len(a))
    65  	for _, s := range a {
    66  		if !f(s) {
    67  			filtered = append(filtered, s)
    68  		}
    69  	}
    70  	return filtered
    71  }
    72  
    73  //Map maps a function across the slice, returning a new slice containing f(s) for s in a
    74  func Map(a []string, f func(string) string) []string {
    75  	mapped := make([]string, len(a))
    76  	for i, s := range a {
    77  		mapped[i] = f(s)
    78  	}
    79  	return mapped
    80  }
    81  
    82  //AppendIfNonEmpty appends the given string(s) to the slice if they are not the empty string.
    83  func AppendIfNonEmpty(a []string, strings ...string) []string {
    84  	for _, s := range strings {
    85  		if s != "" {
    86  			a = append(a, s)
    87  		}
    88  	}
    89  	return a
    90  }
    91  
    92  //Combine multiple slices into a single slice. This is equivalent to appending each slice in turn.
    93  func Combine(slices ...[]string) []string {
    94  	var L int
    95  	for _, a := range slices {
    96  		L += len(a)
    97  	}
    98  	combined := make([]string, 0, L)
    99  	for _, a := range slices {
   100  		combined = append(combined, a...)
   101  	}
   102  	return combined
   103  }
   104  
   105  //Sorted takes any number of input strings and returns a sorted stringslice.
   106  func Sorted(a ...string) []string {
   107  	sort.Strings(a)
   108  	return a
   109  }
   110  
   111  //TotalDistance returns the sum of the levanshtein distance of the strings. If the string slices are not the same length, OK is false.
   112  func TotalDistance(a []string, b []string) (distance int, ok bool) {
   113  	if len(a) != len(b) {
   114  		return 0, false
   115  	}
   116  	for i := range a {
   117  		distance += levenshteinDistance(a[i], b[i])
   118  	}
   119  	return distance, true
   120  }
   121  
   122  // levenshteinDistance measures the difference between two strings.
   123  // The Levenshtein distance between two words is the minimum number of
   124  // single-character edits (i.e. insertions, deletions or substitutions)
   125  // required to change one word into the other.
   126  //
   127  // This implemention is optimized to use O(min(m,n)) space and is based on the
   128  // optimized C version found here:
   129  // http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#C
   130  // This implentation Copyright (c) 2015 Peter Renström under the MIT license: https://github.com/renstrom/fuzzysearch/blob/master/LICENSE
   131  func levenshteinDistance(s, t string) int {
   132  	r1, r2 := []rune(s), []rune(t)
   133  	column := make([]int, len(r1)+1)
   134  
   135  	for y := 1; y <= len(r1); y++ {
   136  		column[y] = y
   137  	}
   138  
   139  	for x := 1; x <= len(r2); x++ {
   140  		column[0] = x
   141  
   142  		for y, lastDiag := 1, x-1; y <= len(r1); y++ {
   143  			oldDiag := column[y]
   144  			cost := 0
   145  			if r1[y-1] != r2[x-1] {
   146  				cost = 1
   147  			}
   148  			column[y] = min(column[y]+1, column[y-1]+1, lastDiag+cost)
   149  			lastDiag = oldDiag
   150  		}
   151  	}
   152  	return column[len(r1)]
   153  }
   154  
   155  func min(a int, ints ...int) int {
   156  	min := a
   157  	for _, n := range ints {
   158  		if n < min {
   159  			min = n
   160  		}
   161  	}
   162  	return min
   163  }