magical expanding hash

braver deliverable at gmail.com
Tue Jan 17 13:39:14 EST 2006


Nice.  What about pushing to leaves which are arrays, or incrementing
leaves which are numbers?  If the array leaf didn't exist, or a number
wasn't set yet, << must create an empty array and push the element from
the RHS into it, and += must init the leaf to 0 and add the RHS to it.
Here's the corresponding ruby:

# ruby!

class MagicalExpandingHash < Hash
  def initialize(*params)
    if params.first.is_a? MagicalExpandingHash
      @parentObj, @parentKey = params[0..1]
      params = params[2..-1]
    end
    super(*params) { |h,k|
      h[k] = MagicalExpandingHash.new(self,k)
    }
  end
  def <<(elem)
    if @parentObj[@parentKey].empty?
      @parentObj[@parentKey] = [ elem ]
    else
      raise ArgumentError, "Can't push onto populated index", caller
    end
  end
  def +(elem)
    unless elem.is_a? Numeric
      raise ArgumentError, "Can't add a non-Numeric value", caller
    end
    if @parentObj[@parentKey].empty?
      @parentObj[@parentKey] = elem
    else
      raise ArgumentError, "Can't add to populated index", caller
    end
  end

  def to_hash
    h = Hash.new
    self.each_pair {|k,v| h[k]=(v.class==self.class)? v.to_hash : v }
    return h
  end

  def from_hash(h)
    h.each_pair {|k,v| self[k]=(v.is_a? Hash) ?
self.class.new.from_hash(v) : v}
  end

  def marshal_dump
    self.to_hash
  end
  def marshal_load(h)
    from_hash(h)
  end
end

# examples
if $0 == __FILE__
  meh = MagicalExpandingHash.new

  meh['usa']['france'] << 'tocqueville'
  meh['usa']['france'] << 'freedom fries'
  meh['life']['meaning'] += 42

  puts meh.inspect
  # => {"usa"=>{"france"=>["tocqueville", "freedom fries"]},
"life"=>{"meaning"=>42}}
end




More information about the Python-list mailing list