class Hash def fast_sort_keys keys = self.keys.sort Hash[keys.zip(self.values_at(*keys))] end # TODO write fast sort values def populate_with_keys(min: nil, max: nil, explicit_default_value: 0) start_key = min || self.keys.min end_key = max || self.keys.max result = self.dup (start_key..end_key).each do |k| result[k] = self[k] || explicit_default_value end return result end # def collapse_values_on_modulo(integer, min: nil, max: nil, shift: nil) # raise ArgumentError.new("Modulo integer had better be larger than shift") if integer <= shift.to_i # # result = Hash.new(0) # hash = self.dup.populate_with_keys(min: min, max: max) # hash = hash.reject{|k, v| k < min.to_i} # hash = hash.reject{|k, v| k > max if max.present?} # # hash.each do |k, v| # if k%integer == shift.to_i # result[k] = (k..(k + integer - 1)).map{|i| hash[i].to_i }.sum # end # end # # return result.fast_sort_keys # end def self.sum(h1, h2) # 1. take keys from both hashes keys = (h1.keys + h2.keys).uniq sum_hash = {} # 2. loop over the keys, summing numerics and recursing into hash-like structures keys.each do |key| v1 = h1[key] v2 = h2[key] sum_value = if v1.respond_to?(:keys) && v2.respond_to?(:keys) # O-1 recuring needed only if both are hash-like sum(v1, v2) elsif v1.present? && v2.blank? # O-3a sum possibe because either is nil (one of the hashes does not have the key at all) v1 elsif v1.blank? && v2.present? # O-3b sum possibe because either is nil (one of the hashes does not have the key at all) v2 elsif v1.respond_to?(:to_f) && v2.respond_to?(:to_f) # O-2 sum possible because both numerics v1 + v2 elsif v1.present? && v2.present? && (v1.respond_to?(:to_f) != v2.respond_to?(:to_f)) # 0-4 error because types mismatch raise ArgumentError.new("Sorry, can not sum these hashes, there's value collision in '#{key}' keys") end sum_hash[key] = sum_value end return sum_hash end end