# Histograms have lots of uses - whenever you need to keep track of the # occurences of items and how many times they've occured, a histogram is # just what's needed. module Eymiha # An exception thrown when adding Arrays to Histograms that cannot be # meaningfully interpretted. class HistogramException < Exception end # A Histogram is a hash whose values are counts of the occurences of the keys. class Histogram < Hash # Creates and returns an instance. If arguments are given, they are passed to # the add method to initialize the new instance. def initialize(key=nil,number=1) super() add(key,number) unless key == nil end # Returns the number of occurences of the given key. If an array of keys # is given, the sum of the number of occurences of those keys is returned. def count(check_keys = keys) check_keys = [check_keys] if ! check_keys.kind_of? Array count = 0 check_keys.each { |key| count += self[key] if has_key? key } count end # Adds the key to the instance if it doesn't already exist, and adds the # specified count to it value. If the key is # * an Array, each member of the array is added. if the member itself is an Array, then if that array has one member, the member is added as a key; if two members, the member is added as a key and a count; otherwise, a HistogramException is thrown. # * another histogram, the keys and counts in the key are added to the instance. def add(key,count=1) if key.kind_of? Array key.each { |member| if member.kind_of? Array if member.size == 1 add(member[0]) elsif (member.size == 2) && (member[1].kind_of? Fixnum) add(member[0],member[1]) else raise HistogramException, "add cannot interpret Array to add" end else add member end } elsif key.kind_of? Histogram key.each_pair { |k,v| add(k,v) } else self[key] = ((value = self[key]) == nil) ? count : value+count end self end # Returns the number of keys in the instance. def key_count keys.size end # Returns a new Histogram containing the elements with occurences greater # than or equal to the given count. def >=(count) result = Histogram.new each_pair { |k,v| result.add(k,v) if v >= count } result end # Returns a new Histogram containing the elements with occurences greater # than the given count. def >(count) result = Histogram.new each_pair { |k,v| result.add(k,v) if v > count } result end # Returns a new Histogram containing the elements with occurences less than # or equal to the given count. def <=(count) result = Histogram.new each_pair { |k,v| result.add(k,v) if v <= count } result end # Returns a new Histogram containing the elements with occurences less than # the given count. def <(count) result = Histogram.new each_pair { |k,v| result.add(k,v) if v < count } result end # If count is a number, a new Histogram containing the elements with # occurences equal to the given countis returned. If the count is a # histogram, true is returned if the instance contains the same keys and # values; false otherwise. def ==(count) if count.kind_of? Numeric result = Histogram.new each_pair { |k,v| result.add(k,v) if v >= count } result else super end end end end