hash of hash and complex data structure

N

ngoc

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
 
N

Nikolai Weibull

ngoc said:
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[c][d] = 1
push @{$a{$b}} = 1;

a << 1

or

a.push 1

or

a.push(1)

(Parentheses are - somewhat - optional.)

Enjoy,
nikolai
 
J

John Carter

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 : (e-mail address removed)
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.
 
J

John Carter

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.
#
# 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( 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.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.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 : (e-mail address removed)
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.
 
R

Robert Klemme

Just for the record, as I don't see any post that actually shows code with
the block in this thread.
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)}
=> # said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Hash search and Interpolation search ? 3
Hash 2
hash of hash? 6
Hash 0
hash of hash of hash of hash in c++ 1
hash 13
Hash 4
hash 6

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top