61d580cc983d52f3dc5050a6858fc788

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.

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 !

E8f0d6e9bc8bca695b3c5bdf75cdcc03

Martin Plöger

March 4, 2010, March 04, 2010 22:30, permalink

No rating. Login to rate!

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'
Dd944f230162411e0cd74ebc62f90b53

Devin Christensen

March 5, 2010, March 05, 2010 01:34, permalink

2 ratings. Login to rate!

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')
25ff3dfe48d3847ecf9971aab99589fb

mxcl

March 5, 2010, March 05, 2010 10:55, permalink

1 rating. Login to rate!

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
E8f0d6e9bc8bca695b3c5bdf75cdcc03

Martin Plöger

March 5, 2010, March 05, 2010 14:14, permalink

1 rating. Login to rate!

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

Your refactoring





Format Copy from initial code

or Cancel