def hash_from_string(string, value)
hash, split = {}, string.split(".")
(split.size-1).downto(0) do |i|
v = i == (split.size-1) ? value : hash
hash = { split[i] => v }
end
hash
end
# use
hash_from_string "some.dot.separated.list", "value"
# expected
{ "some" => { "dot" => { "separated" => { "list" => "value" } } } }
Refactorings
No refactoring yet !
Martin Plöger
March 4, 2010, March 04, 2010 22:30, permalink
Use recursion on a recursive problem...
def hash_from_string string, value
if key = string[/^([^.]+)/]
{key => hash_from_string(string.gsub(/^[^.]+\.?/, ''), value)}
else
value
end
end
#Or shorter (but more cryptic) with the ?-operator
def hash_from_string string, value
(key = string[/^([^.]+)/]) ? {key => hash_from_string(string.gsub(/^[^.]+\.?/, ''), value)} : value
end
p hash_from_string 'some.dot.separated.list', 'value'
Devin Christensen
March 5, 2010, March 05, 2010 01:34, permalink
This is the perfect job for inject. It has the benefit of making it super simple too.
def hash_from_string(string, value)
string.split('.').reverse.inject(value) do |hash, item|
{item => hash}
end
end
p hash_from_string('some.dot.separated.list', 'value')
mxcl
March 5, 2010, March 05, 2010 10:55, permalink
Here's your one liner:
(edit: oops, didn't mean to submit the exact same response as devin, when I came here 10 hours after him it wasn't there, or I'm just really unobservant).
def hash_from_string string, value
string.split('.').reverse.inject(value) { |rv, e| rv = { e => rv } }
end
Martin Plöger
March 5, 2010, March 05, 2010 14:14, permalink
@mxcl, @Devin: I fiddled with #inject, too, but I got it wrong. Great solutions!
@mxcl: You don't have to assign to rv in the inject-block => even shorter: string.split('.').reverse.inject(value) { |rv, e| { e => rv } }
the string can contain 1-n dot-separated keywords and the result should be a nested hash with every keyword being a key and the value being the value of the last key in the string. have fun :)
ps. this is ugly, but i just can't figure out a sane alternative. i think this is clearly a problem to be solved using inject, but i have a problem inserting the value to the last key.