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  }