github.com/seeker-insurance/kit@v0.0.13/counter/string.go (about) 1 //Package counter implements various counter types, analagous to Python's collections.Counter 2 package counter 3 4 import ( 5 "fmt" 6 "sort" 7 "strings" 8 ) 9 10 //String counts the occurence of strings. 11 type String map[string]int 12 13 //Add the the following strings to the counter. 14 func (counter String) Add(items ...string) { 15 for _, item := range items { 16 if _, ok := counter[item]; ok { 17 counter[item]++ 18 } else { 19 counter[item] = 1 20 } 21 } 22 } 23 24 func (counter String) String() string { 25 formatted := make([]string, len(counter)) 26 keys := counter.Keys() 27 sort.Strings(keys) 28 for i, k := range keys { 29 v := counter[k] 30 formatted[i] = fmt.Sprintf("%s:%d", k, v) 31 } 32 return "{" + strings.Join(formatted, ", ") + "}" 33 34 } 35 36 //Count returns counter[string] if it exists, or 0 otherwise. 37 func (counter String) Count(k string) int { 38 n, _ := counter[k] 39 return n 40 } 41 42 //Keys returns the keys of the counter. Order is not guaranteed. 43 func (counter String) Keys() []string { 44 keys := make([]string, len(counter)) 45 var i int 46 for k := range counter { 47 keys[i] = k 48 i++ 49 } 50 return keys 51 } 52 53 func (counter String) MostCommon() (string, int) { 54 mostCommon, max := "", 0 55 for k, v := range counter { 56 if v > max { 57 mostCommon, max = k, v 58 } 59 } 60 return mostCommon, max 61 } 62 63 //MostCommonN returns the N most common keys. In the case of a tie, it prioritizes the lexigraphically lowest, 64 //so that the keys contained in counter.MostCommonN(n) will be identical for two equivalent counters. 65 func (counter String) MostCommonN(n int) (pairs Pairs, err error) { 66 if L := len(counter); L < n { 67 return nil, fmt.Errorf("cannot get %d elemments from a counter with %d elements", L, n) 68 } else if n <= 0 { 69 return nil, fmt.Errorf("must take a positive integer, but had %d", n) 70 } 71 pairs = make(Pairs, n) 72 for k, v := range counter { 73 for i, p := range pairs { 74 if c := p.Count; v > c || v == c && k < p.Key { 75 copy(pairs[i+1:], pairs[i:n-1]) 76 pairs[i] = Pair{k, v} 77 break 78 } 79 } 80 } 81 return pairs, nil 82 } 83 84 //Pairs returns a slice containing each key-value pair 85 func (counter String) Pairs() Pairs { 86 pairs := make(Pairs, len(counter)) 87 var i int 88 for k, c := range counter { 89 pairs[i] = Pair{k, c} 90 i++ 91 } 92 return pairs 93 } 94 95 //Sorted returns the keys and coutns of the strings in the counter. They are sorted by the count, and then by the key. 96 //i.e, given {"c": 1, "b": 3, "a":3}, returns {1, 1, 3}, {c, a, b} 97 func (counter String) Sorted() Pairs { 98 pairs := counter.Pairs() 99 sort.Sort(pairs) 100 return pairs 101 } 102 103 //Combine one or more counters, where the count of each element is the sum of the count of each 104 func (counter String) Combine(counters ...String) String { 105 combined := counter.Copy() 106 for _, c := range counters { 107 for key, val := range c { 108 if _, ok := counter[key]; ok { 109 combined[key] += val 110 } else { 111 combined[key] = val 112 } 113 } 114 } 115 return combined 116 } 117 118 //Equal returns true if two counters are equal. Two counters are equal if they have the same length and share all keys and values. 119 func (counter String) Equal(other String) bool { 120 if len(counter) != len(other) { 121 return false 122 } 123 for k, v := range counter { 124 if v == 0 { 125 if b, _ := other[k]; b != v { 126 return false 127 } 128 } else if b, ok := other[k]; !ok || b != v { 129 return false 130 } 131 132 } 133 return true 134 } 135 136 //Neg returns a copy of the counter with inverted counts: i.e, {k: -v for k, v in counter} 137 func (counter String) Neg() String { 138 negated := make(String) 139 for k, v := range counter { 140 negated[k] = -v 141 } 142 return negated 143 } 144 145 //NonZeroElements returns a copy of the counter with all dummy elements(count zero) removed. 146 func (counter String) NonZeroElements() String { 147 copy := make(String) 148 for k, v := range counter { 149 if v != 0 { 150 copy[k] = v 151 } 152 } 153 return copy 154 } 155 156 //PositiveElements returns a copy of counter containing all the elements where the counter[x] > 0 157 func (counter String) PositiveElements() String { 158 copy := make(String) 159 for k, v := range counter { 160 if v > 0 { 161 copy[k] = v 162 } 163 } 164 return copy 165 } 166 167 //Copy the counter 168 func (counter String) Copy() String { 169 copy := make(String) 170 for k, v := range counter { 171 copy[k] = v 172 } 173 return copy 174 } 175 176 //Min returns a counter minC where minC[x] = min(max(c[x], 0) for c in counters) 177 func Min(counters ...String) String { 178 min := make(String) 179 for _, c := range counters { 180 for key, val := range c { 181 if _, ok := min[key]; ok { 182 if val < min[key] { 183 min[key] = val 184 } 185 } else { 186 min[key] = val 187 } 188 } 189 } 190 return min 191 } 192 193 //Max returns a counter maxC where maxC[x] = max(c[x] for c in counters) 194 func Max(counters ...String) String { 195 max := make(String) 196 for _, c := range counters { 197 for key, val := range c { 198 if _, ok := max[key]; ok { 199 if val > max[key] { 200 max[key] = val 201 } 202 } else { 203 max[key] = val 204 } 205 } 206 } 207 return max 208 } 209 210 //FromStrings creates a counter of strings from a slice, counting each member once. 211 func FromStrings(strings ...string) String { 212 counter := make(String) 213 counter.Add(strings...) 214 return counter 215 }