Reputation: 1214
So I'm trying to make a tree data structure, which can be instantiated by a nested hash.
My code is as follows, and should just recursively make nodes out of keys, and children out of their values.
class Tree
attr_accessor :children, :node_name
#def initialize(name, children=[])
# @children = children
# @node_name = name
# end
def initialize(hashTree)
@node_name = hashTree.keys[0]
@children = []
p node_name
hashTree[node_name].each do |hash|
children << Tree.new(hash)
end
end
#...
end
p = {'grandpa' => { 'dad' => {'child 1' => {}, 'child2' => {} }, 'uncle' => {'child 3' => {}, 'child 4' => {} } } }
p p
p Tree.new(p)
When I try to run that code I get the following:
{"grandpa"=>{"dad"=>{"child 1"=>{}, "child2"=>{}}, "uncle"=>{"child 3"=>{}, "child 4"=>{}}}}
"grandpa"
/Users/Matt/sw/sevenLang/week1/hw-tree.rb:8:in `initialize': undefined method `keys' for ["dad", {"child 1"=>{}, "child2"=>{}}]:Array (NoMethodError)
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:12:in `new'
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:12:in `block in initialize'
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:11:in `each'
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:11:in `initialize'
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:26:in `new'
from /Users/Matt/sw/sevenLang/week1/hw-tree.rb:26:in `<main>'
[Finished in 0.1s with exit code 1]
It looks like each is turning the nested hash into an array, where the key is the first element, and the value is the second element.
Upvotes: 0
Views: 44
Reputation: 198496
hashTree[node_name]
is p["grandpa"]
, and is a Hash:
{"dad"=>{"child 1"=>{}, "child2"=>{}}, "uncle"=>{"child 3"=>{}, "child 4"=>{}}}
Hash#each
will yield a two-element array: a key and a value. So if you write
hashTree[node_name].each do |hash|
and hashTree[node_name]
is a Hash, hash
will always be a two-element array. Due to a trick in its grammar, Ruby will auto-splat an array argument if there are multiple formal parameters, so you can also write:
hashTree[node_name].each do |name, hash|
This will not result in an error. (You do actually still have an unrelated error in logic, as you're skipping a level.)
An error-free version:
class Tree
attr_accessor :children, :node_name
def initialize(name, hashTree)
@node_name = name
@children = []
hashTree.each do |child_name, hash|
children << Tree.new(child_name, hash)
end
end
end
p = {'grandpa' => { 'dad' => {'child 1' => {}, 'child2' => {} }, 'uncle' => {'child 3' => {}, 'child 4' => {} } } }
p Tree.new("Family", p)
This can be shortened by using map
:
class Tree
attr_accessor :children, :node_name
def initialize(name, hashTree)
@node_name = name
@children = hashTree.map do |child_name, hash|
Tree.new(child_name, hash)
end
end
end
Upvotes: 2