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 }