Hi,
I’m banging my head against the wall with the following problem:
array = [“home”, “about”, “about/history”, “about/company”,
“about/history/part1”, “about/history/part2”]
I want to build a tree from this array in the form of a nested hash:
{“home” => nil, "about => {“history => [“part1” => nil, “part2” =>
nil]”, “company” => nil}}
Any ideas as to how best to solve this?
Regards
Adam
On 2/11/08, Adam G. [email protected] wrote:
I could only figure out how to do it using 2 passes:
tree ={}
array.sort.each{|w|
h=tree
w.split(‘/’).each{|part| h=h[part]||=Hash.new}
}
def cleanup h
return true if h.empty?
h.find_all{|k,v|h[k]=nil if v.is_a?(Hash)&&cleanup(v)}
false
end
cleanup tree
p tree
=> {“about”=>{“company”=>nil, “history”=>{“part1”=>nil,
“part2”=>nil}}, “home”=>nil}
-Adam
On Feb 11, 4:43 pm, Adam G. [email protected] wrote:
nil]", “company” => nil}}
Your output doesn’t seem consistent. (Why an array sometimes but a
hash others?)
Here’s something simple and close:
array = [“home”, “about”, “about/history”, “about/company”, “about/
history/part1”, “about/history/part2”]
auto_hash = Hash.new{ |h,k| h[k] = Hash.new &h.default_proc }
array.each{ |path|
sub = auto_hash
path.split( “/” ).each{ |dir| sub[dir]; sub = sub[dir] }
}
p auto_hash
#=> {“about”=>{“company”=>{}, “history”=>{“part1”=>{}, “part2”=>{}}},
“home”=>{}}
On Feb 11, 10:00 pm, Phrogz [email protected] wrote:
array.each{ |path|
sub = auto_hash
path.split( “/” ).each{ |dir| sub[dir]; sub = sub[dir] }
}
Bah, of course that can be written as:
array.each{ |path|
sub = auto_hash
path.split( “/” ).each{ |dir| sub = sub[dir] }
}
Gavin K. wrote:
On Feb 11, 10:00�pm, Phrogz [email protected] wrote:
array.each{ |path|
� sub = auto_hash
� path.split( “/” ).each{ |dir| sub[dir]; sub = sub[dir] }
}
Bah, of course that can be written as:
array.each{ |path|
sub = auto_hash
path.split( “/” ).each{ |dir| sub = sub[dir] }
}
Gavin,
thanks mate - works a charm. I’m glad you spotted my deliberately
inconsistent output as well! 
Adam
2008/2/12, Phrogz [email protected]:
path.split( “/” ).each{ |dir| sub = sub[dir] }
}
Or even
array.each{ |path|
path.to_enum(:split, “/” ).inject(auto_hash){ |sub, dir| sub[dir] }
}
Full credits go to you for this line alone:
auto_hash = Hash.new{ |h,k| h[k] = Hash.new &h.default_proc }
Never occurred to me to use this nice one line approach instead of the
usual two line version (first create block then use it). Thanks a
lot, this is really a gem!
Kind regards
robert
On Feb 12, 7:12 am, Robert K. [email protected] wrote:
Full credits go to you for this line alone:
auto_hash = Hash.new{ |h,k| h[k] = Hash.new &h.default_proc }
Never occurred to me to use this nice one line approach instead of the
usual two line version (first create block then use it). Thanks a
lot, this is really a gem!
I wish I could claim those credits. I had always used the two-line
version two until Jens W. posted this gem in [ruby-talk:288946]
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/288946
Alternatively:
require ‘xkeys’
array = [“home”, “about”, “about/history”, “about/company”,
“about/history/part1”, “about/history/part2”]
tree = {}.extend XKeys::Hash
array.each { |path| tree[*(path.split ?/)] = nil }
p tree
{“home”=>nil, “about”=>{“history”=>{“part1”=>nil, “part2”=>nil},
“company”=>nil}}
The leaves are nil (not empty hashes), and the code is slightly less
convoluted.
On 12.02.2008 15:30, Phrogz wrote:
version two until Jens W. posted this gem in [ruby-talk:288946]
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/288946
Ok, then you get at least part of the credits for bringing it up again.

Kind regards
robert