Hash of hash and complex data structure

Hi
I am perl programmer, looking for new tools and interested in Ruby
How in ruby similar to perl
$a{$b}{$c}{$d} = 1;
push @{$a{$b}} = 1;
Thanks
ngoc

ngoc wrote:

How in ruby similar to perl
$a{$b}{$c}{$d} = 1;

Wasn’t this question asked but yesterday? You may find a lot of useful
information on rubygarden.org and ruby-talk.org.

The answer is

a[b][c][d] = 1

push @{$a{$b}} = 1;

a[b] << 1

or

a[b].push 1

or

a[b].push(1)

(Parentheses are - somewhat - optional.)

Enjoy,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

I am perl programmer, looking for new tools and interested in Ruby
How in ruby similar to perl
$a{$b}{$c}{$d} = 1;

Ruby doesn't quite have the auto-vivification that perl has. You have to be a little more explicit about specifying what the behaviour of the hash on accessing a uninited key should be eg..
Perl $a{fred}++
Will assume "quotes" around the fred, and the autovivify the $a{"fred"} as 0 as you are adding one to it. Ruby doesn't quite do either.

You get something similar in Ruby by..
a = Hash.new(0)
a["fred"]+=1

You can get fancier in Ruby with...
a = Hash.new {|hash,key| hash[key] = Hash.new{
                  >hash,key| hash[key] = Hash.new(0)
              }}
a["tom"]["dick"]["harry"] += 1

On the other hand autovivifivation is a _very_ suprising feature of perl that took me years to find out about. I prefer ruby's more explicit approach.

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong later."

From this principle, all of life and physics may be deduced.

···

On Fri, 27 May 2005, ngoc wrote:

Just for the record, as I don't see any post that actually shows code with
the block in this thread.

ngoc wrote:

Hi
I am perl programmer, looking for new tools and interested in Ruby
How in ruby similar to perl
$a{$b}{$c}{$d} = 1;

missing = lambda {|h,k| h[k] = Hash.new(&missing)}

=> #<Proc:0x10185800@(irb):21>

h = Hash.new(&missing)

=> {}

h[1][2][3] = 4

=> 4

h

=> {2=>{3=>4}}

push @{$a{$b}} = 1;

h = Hash.new {|h,k| h[k] = }

=> {}

h[1].push 2

=> [2]

h

=> {1=>[2]}

Kind regards

    robert

Oh yes, just as an aside, as a perl programmer I use to create quite a lot of these complex structures.

As a ruby programmer I hardly ever do that. Not because ruby lacks the facility, but because I have found when I come back to the code three months later I haven't the faintest idea what the hell is going on.

So these days I make use of the fact that it is really _very_ easy to spin a new class in Ruby or even extend Hash and I now make a bunch of small classes instead of hairy hash of hash structures. It is just so much easy to get my head around it.

The only survivor of those perlish habits is my nifty ChainedHash class which I often use. (I see it was written before I discovered the block option on Hash.new)

# A ChainedHash is a Hash that
# stores every value in an array.

···

On Fri, 27 May 2005, John Carter wrote:

On Fri, 27 May 2005, ngoc wrote:

I am perl programmer, looking for new tools and interested in Ruby
How in ruby similar to perl
$a{$b}{$c}{$d} = 1;

#
# However , "chained_hash[key]=value", a new value over an old one
# doesn't replace the old one, it merely pushes it onto the end of the array.
#
class ChainedHash < Hash

   # Last in first out.
   def lifo(key)
     fetch(key)[-1]
   end

   # Last in first out.
   def fifo(key)
     fetch(key)[0]
   end

   # Push value onto the the end of the array associated with key.
   # if the hash doesn't have that key, stores [value]
   def =(key,value)
     if has_key? key then
       fetch(key).push( value)
     else
       store(key, [value])
     end
   end

   # Push value onto the the end of the array associated with key,
   # iff it isn't already there
   # if the hash doesn't have that key, stores [value]
   def store_unique(key, value)
     if has_key? key then
       array = fetch(key)
       array.push( value) unless array.include? value
     else
       store(key, [value])
     end
   end

   def (key)
     if has_key? key then
       fetch(key)
     else
       result =
       store(key, result)
       result
     end
   end

   # Iterates over each value array and each element in each array.
   def each_value(&block)
     super {|v| v.each(&block)}
   end

   # Iterates over each value array and each element in each array yielding key,value
   def each_key_value
     self.each_key do |key|
       self[key].each do |value|
         yield key,value
       end
     end
   end

   # Partition an enumerable based on whatever criteria is given in block
   # For example ChainedHash.multi_partition( %w{a b c aa d ddd ff}) {|e| e.length}
   # results in {1=>[a,b,c d], 2=>[aa, ff], 3=>[ddd]}
   #
   # For each element in any Enumerable enum, invoke block with that
   # element and accumulate the result in a chained hash.

   def ChainedHash.multi_partition(enum,&block)
     map = ChainedHash.new
     enum.each do |i|
       map[block.call(i)] = i
     end
     return map
   end

end

if $0 == __FILE__ then
   require 'test/unit'
   require 'yaml'

   class TC_ChainedHash < Test::Unit::TestCase
     def test_yaml
       h = ChainedHash.new
       h[:a] = 1
       h[:a] = 2
       h[:a] = 3
       h[:a] = 4
       h[:b] = 1
       i = YAML::dump(h)
       j = YAML::load(i)
       assert_equal( h, j)
     end

     def test_each_value
       h = ChainedHash.new
       h[:a] = 1
       h[:a] = 2
       h[:a] = 3
       h[:a] = 4
       h[:b] = 1

       c =
       h.each_value do |e|
         c << e
       end
       assert_equal( [1,1,2,3,4], c.sort)
     end

     def test_fetch
       h = ChainedHash.new
       assert_equal( , h[3])
     end

     def test_uniq
       h = ChainedHash.new
       h.store_unique( 1, 'a')
       h.store_unique( 2, 'a')
       h.store_unique( 1, 'a')
       h.store_unique( 1, 'b')

       assert_equal( 2, h.keys.length)
       assert_equal( 2, h[1].length)
       assert_equal( 1, h[2].length)
       assert_equal( 'a', h[2][0])
     end

     def test_lifo
       h = ChainedHash.new
       h['a'] = 'x1'
       assert_equal( h.lifo( 'a'), 'x1')
       h['c'] = 'x2'
       assert_equal( h.lifo('c'), 'x2')
       h['a'] = 'x3'
       assert_equal( h.lifo('a'), 'x3')
       assert_equal( h['a'], ['x1','x3'])
     end

     def test_fifo
       h = ChainedHash.new
       h['a'] = 'x1'
       assert_equal( h.fifo('a'), 'x1')
       h['c'] = 'x2'
       assert_equal( h.fifo('c'), 'x2')
       h['a'] = 'x3'
       assert_equal( h.fifo('a'), 'x1')
       assert_equal( h['a'], ['x1', 'x3'])
     end

     def test_multi_part
       mp = ChainedHash.multi_partition( %w{a b c aa d ddd ff}) {|e| e.length}
       assert_equal( mp.keys.length, 3)
       assert_equal( mp[1], %w{a b c d})
     end
   end

end

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong later."

From this principle, all of life and physics may be deduced.