Nested hash from array of paths

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

···

--
Posted via http://www.ruby-forum.com/.

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 2/11/08, Adam Groves <adam.groves@gmail.com> wrote:

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?

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, 4:43 pm, Adam Groves <adam.gro...@gmail.com> wrote:

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}}

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.

···

--
Posted via http://www.ruby-forum.com/.

Bah, of course that can be written as:

array.each{ |path|
  sub = auto_hash
  path.split( "/" ).each{ |dir| sub = sub[dir] }
}

···

On Feb 11, 10:00 pm, Phrogz <phr...@mac.com> wrote:

array.each{ |path|
sub = auto_hash
path.split( "/" ).each{ |dir| sub[dir]; sub = sub[dir] }
}

Gavin Kistner wrote:

···

On Feb 11, 10:00�pm, Phrogz <phr...@mac.com> 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! :wink:

Adam
--
Posted via http://www.ruby-forum.com/\.

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

···

2008/2/12, Phrogz <phrogz@mac.com>:

On Feb 11, 10:00 pm, Phrogz <phr...@mac.com> 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] }
}

--
use.inject do |as, often| as.you_can - without end

Registration is now open for Gotham Ruby Conference [GoRuCo] 2008, a
one-day, single-track technical conference, aimed at highly motivated
programmers, in New York City and dedicated to everything Ruby.

The conference will be held on

Saturday, April 26th at the Manhattan campus of Pace University.

Registration is $125 per person and includes lunch.

Based on last year's enthusiastic response, we expect this conference to
sell out, so purchase your tickets early!

Register here:

http://goruco2008.eventwax.com/gotham-ruby-conference-goruco-2008/regist
er
<blocked::http://goruco2008.eventwax.com/gotham-ruby-conference-goruco-2
008/register>

GoRuCo 2008 Speakers:

Giles Bowkett
Archaeopteryx: A Ruby MIDI Generator

Paul Dix
Collective Intelligence: Leveraging User Data to Create Intelligent
Rails Applications

Bryan Helmkamp
Story Driven Development: The Next Generation of Rails Functional
Testing

Alex Payne
Twitter

Chris Wanstrath
Forbidden Fruit: A Taste of Ruby's Parse Tree

Ezra Zygmuntowicz
Merb, All you need, None you don't

For more information, visit : http://2008.goruco.com/
<blocked::http://2008.goruco.com/>

<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
The information in this email and any attachments may contain
confidential information that is intended solely for the
attention and use of the named addressee(s). This message or
any part thereof must not be disclosed, copied, distributed
or retained by any person without authorization from the
addressee. If you are not the intended addressee, please
notify the sender immediately, and delete this message.
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

I wish I could claim those credits. I had always used the two-line
version two until Jens Wille posted this gem in [ruby-talk:288946]

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/288946

···

On Feb 12, 7:12 am, Robert Klemme <shortcut...@googlemail.com> 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!

Ok, then you get at least part of the credits for bringing it up again. :wink:

Kind regards

  robert

···

On 12.02.2008 15:30, Phrogz wrote:

On Feb 12, 7:12 am, Robert Klemme <shortcut...@googlemail.com> 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 Wille posted this gem in [ruby-talk:288946]

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/288946