On 23/08/05, William James <w_a_x_man / yahoo.com> wrote:
> David A. Black wrote:
> > Hi --
> >
> > On Tue, 23 Aug 2005, William James wrote:
> >
> > > Phrogz wrote:
> > >> To be clear, what Bill is saying is that you need to use pHash.call to
> > >> create your hash, and call the Hash methods on that. Like so:
> > >>
> > >> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
> > >>
> > >> uberhash = pHash.call
> > >>
> > >> uberhash['L']['a'] = "one"
> > >> p uberhash.keys        #=> ["L"]
> > >> p uberhash['L'].keys   #=> ["a"]
> > >> p uberhash['L'].values #=> ["one"]
> > >
> > > How would you test to see if this exists?
> > >
> > > h[9][8][7][6][5][4][3][2][1]
> >
> > I think it exists as soon as you refer to it.  (I thought that's the
> > whole point :-)  But if you didn't want that to happen I guess you
> > could do:
> >
> >    if h[9][8][7][6][5][4][3][2].has_key?(1) ...
> 
> It's not the whole point. One needs to be able to check
> to see if an entry exists without changing the hash.
> 
> irb(main):002:0> h=pHash.call
> => {}
> irb(main):003:0> h['foo']=999
> => 999
> irb(main):005:0> if h[9][8][7][6][5][4][3][2].has_key?(1) then puts
> 'ok';end
> => nil
> irb(main):006:0> p h
> {"foo"=>999, 9=>{8=>{7=>{6=>{5=>{4=>{3=>{2=>{}}}}}}}}}
> 
> Even lowly Awk can easily do this.
> -------------------------------------------------
> BEGIN {
>   a[9,8,7,6,5,4,3,2,1] = "yes"
>   if ( (9,8,7,6,5,4,3,2,1) in a )
>     print "o.k."
>   if ( (0,8,7,6,5,4,3,2,1) in a )
>     print "not o.k."
>   if ( (0,8,7,6,5,4,3,2) in a )
>     print "not o.k."
>   print length(a)
> }
> -------------------------------------------------
> Output:
> 
> o.k.
> 1
> 
> 
> 

Ruby does what you ask it to do. Just as an example I took my
autovivifying array example and converted it into an auto-hash.

class AutoHash < Hash
  def initialize(*args)
    super()
    @update, @update_index = args[0][:update], args[0][:update_key]
unless args.empty?
  end
  
  def [](k)
    if self.has_key?k
      super(k)
    else
      AutoHash.new(:update => self, :update_key => k)
    end
  end

  def []=(k, v)
    @update[@update_index] = self if @update and @update_index
    super
  end
end

a  = AutoHash.new
a[1][2][3] = 12
p a
a[2][3][4]   
p a
a[1][-2][1] = "Negative"
p a
p a[4][5][6].has_key? 7
p a

Does this do what you think you need. 

As a sidenote, I never felt the need for auto-hashes nor auto-arrays.
Ruby just makes it so simple to write clean code with specialized
container-classes for the job, that this was never neccessary. Anyway,
it was a nice exercise, so thanks for the challenge.

Brian



-- 
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/