aaronrussell
aaronrussell

Reputation: 9467

Convert a hash tree into array of hashes with depth key

Given a hash tree like this:

hash_tree = {
  <Category id: 1, title: "foo"> => {},
  <Category id: 2, title: "bar"> => {
    <Category id: 3 title: "baz"> => {
      <Category id: 4 title: "qux"> => {}
    }
  },
  <Category id: 5, title: "norf"> => {}
}

I would like an elegant way of creating a flat array of hashes, with order preserved, with the depth added to each hash as a key, eg:

flat_array = [
  { value: 1, text: "foo", depth: 0 },
  { value: 2, text: "bar", depth: 0 },
  { value: 3, text: "baz", depth: 1 },
  { value: 4, text: "quz", depth: 2 },
  { value: 5, text: "norf", depth: 0 }
]

Each of the objects that make up the hash tree are quite a bit more complex than in the example above with more attributes, but all I need in my array is the ID and title - but note that the keys have changed.

Thanks

Upvotes: 2

Views: 407

Answers (1)

Anthony
Anthony

Reputation: 15967

I changed your hash_tree to open structs so I could work with it but I think I got what you are after:

require 'ostruct'

hash_tree = {
  OpenStruct.new(id: 1, title: "foo") => {},
  OpenStruct.new(id: 2, title: "bar") => {
    OpenStruct.new(id: 3, title: "baz") => {
      OpenStruct.new(id: 4, title: "qux") => {}
    }
  },
  OpenStruct.new(id: 5, title: "norf") => {}
}


def flat_tree(hash, depth = 0)
  hash.each_with_object([]) do |(obj, v), results|
    results << { value: obj.id, text: obj.title, depth: depth }
    results << flat_tree(v, depth + 1) if v.is_a?(Hash) && !v.empty?
  end
end

puts flat_tree(hash_tree)

output:

{:value=>1, :text=>"foo", :depth=>0}
{:value=>2, :text=>"bar", :depth=>0}
{:value=>3, :text=>"baz", :depth=>1}
{:value=>4, :text=>"qux", :depth=>2}
{:value=>5, :text=>"norf", :depth=>0}

Upvotes: 2

Related Questions