Eugen
Eugen

Reputation: 155

Convert String to Hash

Im wondering if there is a better way of converting a string to a Hash. My String will always look exactly the same regarding the structure. Here is an example:

string = "range:12\ntype:default\n"

@settings = Hash[
  *string.downcase
  .split("\n")
  .map{|s| [s.split(":")[0].to_sym, s.split(":")[1]]}
  .flatten
]

p @settings
# => {:range=>"12", :type=>"default"}

This does what it should do and I have no problems with this. But it is extremely unreadable and I hope that there are some refactoring options for my code.

Upvotes: 2

Views: 3351

Answers (5)

Santhosh
Santhosh

Reputation: 29124

Hash[*string.split(/[:\n]/)]
# => {"range"=>"12", "type"=>"default"} 

Upvotes: 6

Patrick Oscity
Patrick Oscity

Reputation: 54684

You can use String.scan to search for key-value pairs in the string and then convert the resulting array of arrays to a hash by simply calling to_h:

string.scan(/(.+):(.+)\n/).to_h
#=> {"range"=>"12", "type"=>"default"}

If you really need the symbol keys, you can use Array#map before converting to a hash:

string.scan(/(.+):(.+)\n/).map {|k,v| [k.to_sym, v]}.to_h
#=> {:range=>"12", :type=>"default"}

If you're using Rails, there's already the built in method Hash#symbolize_keys:

string.scan(/(.+):(.+)\n/).to_h.symbolize_keys
#=> {:range=>"12", :type=>"default"}

Upvotes: 5

Stefan
Stefan

Reputation: 114178

This would work:

string = "range:12\ntype:default\n"

string.split("\n").each_with_object({}) { |s, h|
  k, v = s.split(':')
  h[k.to_sym] = v
}
#=> {:range=>"12", :type=>"default"}

Upvotes: 3

Marek Lipka
Marek Lipka

Reputation: 51151

If you had spaces before your values:

string = "range: 12\ntype: default\n"

This string would be correct YAML, so you could parse it with Ruby yaml library:

require 'yaml'
string = "range: 12\ntype: default\n"
@settings = YAML.load(string)
# => {"range"=>12, "type"=>"default"}

So I suggest modifying your settings format a little bit, if you can do it.

Upvotes: 3

falsetru
falsetru

Reputation: 369074

Hash::[] can handle array of arrays:

@settings = Hash[
  string.split("\n")
  .map { |s| s = s.split(":"); [s[0].to_sym, s[1]] }
]

Upvotes: 2

Related Questions