From: "Brian Schröder" Date: 2005-08-23T18:34:53+09:00 Subject: Re: No Keys, nor other hash methods on multidimensional hash On 23/08/05, William James 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/