gamnit: make `SpriteSet` public so clients can use its services
[nit.git] / lib / counter.nit
index befce9c..e539bc5 100644 (file)
@@ -80,6 +80,12 @@ class Counter[E]
                map.clear
        end
 
+       redef fun add_all(other) do
+               for k, v in other do
+                       self[k] += v
+               end
+       end
+
        # Count one more occurrence of `e`
        fun inc(e: E)
        do
@@ -133,6 +139,7 @@ class Counter[E]
        # @toimplement by default just call `to_s` on the element
        protected fun element_to_s(e: E): String
        do
+               if e == null then return "null"
                return e.to_s
        end
 
@@ -254,6 +261,81 @@ class Counter[E]
                end
                return (sum / map.length.to_f).sqrt
        end
+
+       # The information entropy (Shannon entropy) of the elements in the counter (in bits).
+       fun entropy: Float
+       do
+               var res = 0.0
+               var sum = self.sum.to_f
+               for k, v in self do
+                       var f = v.to_f / sum
+                       res = res - f * f.log_base(2.0)
+               end
+               return res
+       end
+
+       # Prints the content of the counter along with statistics
+       #
+       # Content is printed in order (if available) from lowest to highest on the keys.
+       # Else, it is printed as-is
+       fun print_content do
+               var a = keys.to_a
+               if a isa Array[Comparable] then default_comparator.sort(a)
+               var subtotal = 0
+               for i in a do
+                       subtotal += self[i]
+                       printn("* ", i or else "null", " = ", self[i], " => occurences ", self[i].to_f / sum.to_f * 100.0, "%, cumulative ", subtotal.to_f / sum.to_f * 100.0, "% \n")
+               end
+       end
+
+       # Packs elements into separate arrays based on their occurences
+       #
+       # ~~~nit
+       #       var x = "aaaabbbeeecccddhhgjt"
+       #       var c = new Counter[Char]
+       #       for i in x do c.inc i
+       #       var ret = c.pack
+       #       assert ret.join(", ") == """[t,g,j], [d,h], [c,b,e], [a]"""
+       # ~~~
+       fun pack: Array[Array[E]] do
+               var ret = new Array[Array[E]]
+               var base = self.sort
+               if base.is_empty then return ret
+               var curr = new Array[E]
+               curr.push base.first
+               var curr_score = self[base.first]
+               base.shift
+               for i in base do
+                       if self[i] == curr_score then
+                               curr.push i
+                               continue
+                       end
+                       curr_score = self[i]
+                       ret.push curr
+                       curr = new Array[E]
+                       curr.push i
+               end
+               if not curr.is_empty then ret.push curr
+               return ret
+       end
+end
+
+redef class Collection[E]
+       # Create and fill up a counter with the elements of `self.
+       #
+       # ~~~
+       # var cpt = "abaa".chars.to_counter
+       # assert cpt['a'] == 3
+       # assert cpt['b'] == 1
+       # assert cpt.length == 2
+       # assert cpt.sum == 4
+       # ~~~
+       fun to_counter: Counter[E]
+       do
+               var res = new Counter[E]
+               res.inc_all(self)
+               return res
+       end
 end
 
 private class CounterComparator[E]