I have an array eg. arr = [:a, :b, :c] and i would like to make a hash from it in the form of
[{:a => [{:b => [:c] } ] } ]
I have an array eg. arr = [:a, :b, :c] and i would like to make a hash from it in the form of
[{:a => [{:b => [:c] } ] } ]
Quick and dirty:
[{ arr.shift => [{ arr.shift => [arr.shift] }] }]
To Cary's point, this is a little less dirty:
[{ arr[0] => [{ arr[1] => [arr[2]] }] }]
Or:
enum = arr.each
[{ enum.next => [{ enum.next => [enum.next] }] }]
If you're looking for something a little more flexible, here's a recursive method that does it:
def nest(arr)
head, *tail = arr
return [head] if tail.empty?
[{ head => nest(tail) }]
end
nest([:a, :b, :c]) # => [{:a=>[{:b=>[:c]}]}]
nest(head, *tail) and call it like nest(*tail).arr.shift always gets evaluated first, followed by the one in the middle, before the one on the right? If a different Ruby version evaluates things in a different order, your results will change.[{ arr[0] => [{ arr[1] => [arr[2] }] }] (which, incidentally, doesn't mutate arr)?key = evaluate_key_expr(); value = evaluate_value_expr(); add_to_hash(key, value); Some programmer might reorder the first two lines some day (so a hash value gets evaluated before the corresponding key) and it would not break most Ruby programs, but it would break your quick and dirty one.If you don’t hesitate to mutate an input:
loop.inject([]) do |memo|
break memo unless e = arr.pop
[memo.empty? ? e : {e => memo}]
end
To not mutate the initial array arr, call dup on it in advance, or use iterator:
iter = arr.reverse.each
loop.inject([]) do |memo|
break memo unless e = iter.next
[memo.empty? ? e : {e => memo}]
end
You can get something close with inject:
arr.reverse.inject([]) { |memo, item| [{item => memo }] }
# => [{:a=>[{:b=>[{:c=>[]}]}]}]
and thanks to the comment by Cary, spot on:
arr.reverse.inject([]) { |memo, item| memo.empty? ? [item] : [{item => memo }] }
# => [{:a=>[{:b=>[:c]}]}]
arr.reverse.inject([]) { |memo, item| memo.empty? ? [item] : [{item => memo }] } #=> [{:a=>[{:b=>[:c]}]}].