core::hash_collection: native array storage is no more nullable
[nit.git] / lib / counter.nit
index 6545b73..9a539e6 100644 (file)
@@ -53,14 +53,14 @@ class Counter[E]
        redef fun iterator do return map.iterator
 
        # The number of counted occurrences of `e`
-       redef fun [](e: E): Int
+       redef fun [](e)
        do
                var map = self.map
                if map.has_key(e) then return map[e]
                return 0
        end
 
-       redef fun []=(e: E, value: Int)
+       redef fun []=(e, value)
        do
                sum -= self[e]
                self.map[e] = value
@@ -93,6 +93,22 @@ class Counter[E]
                for e in es do inc(e)
        end
 
+       # Decrement the value of `e` by 1
+       fun dec(e: E) do
+               if not has_key(e) then
+                       self.map[e] = 0
+               else
+                       self.map[e] = self[e] - 1
+                       sum += - 1
+               end
+       end
+
+       # Decrement the value for each element of `es`
+       fun dec_all(es: Collection[E])
+       do
+               for e in es do dec(e)
+       end
+
        # A new Counter initialized with `inc_all`.
        init from(es: Collection[E])
        do
@@ -238,6 +254,50 @@ 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
+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]