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.