Reputation: 1620
I have an array of hashes:
@operating_systems = [
{"title"=>"iPhone", "value_percent"=>"42.6"},
{"title"=>"Windows 7", "value_percent"=>"21.3"},
{"title"=>"Android", "value_percent"=>"12.8"},
{"title"=>"Mac OS X", "value_percent"=>"8.5"},
{"title"=>"Windows 8.1", "value_percent"=>"6.4"},
{"title"=>"Windows XP", "value_percent"=>"4.3"},
{"title"=>"Linux", "value_percent"=>"2.1"},
{"title"=>"Windows Vista", "value_percent"=>"2.1"}
]
and want to create the following hash:
{"iphone" => "42.6", "windows 7" => "21.3", ... "windows vista" => "2.1"}
What is the best way to accomplish this?
Upvotes: 0
Views: 90
Reputation: 61975
While there are a number of more clever approaches, a simple loop over the source array with modification of the output hash will suffice; consider
arr = [{"title"=>"iPhone", "value_percent"=>"42.6"}, ..]
hash = {}
arr.each do |item|
key = item["title"]
value = item["value_percent"]
hash[key] = value
end
and see the ideone demo. This is a very easy task, and I hope that how it was "solved" is made readily apparent above - there is no "best" until there is "working".
Once the basic approach is understood, the same process that was done (a transformation and then building a map from pairs) can be done as so
hash = Hash[arr.map do |v| [v["title"], v["value_percent"]] end]
Is this "better"? shrug, I guess it's "shorter" and still clear.. (and any additional transformation can be trivially added)
Upvotes: 0
Reputation: 160621
@Sawa came the closest to what I'd do:
operating_systems = [
{"title"=>"iPhone", "value_percent"=>"42.6"},
{"title"=>"Windows 7", "value_percent"=>"21.3"},
{"title"=>"Android", "value_percent"=>"12.8"},
{"title"=>"Mac OS X", "value_percent"=>"8.5"},
{"title"=>"Windows 8.1", "value_percent"=>"6.4"},
{"title"=>"Windows XP", "value_percent"=>"4.3"},
{"title"=>"Linux", "value_percent"=>"2.1"},
{"title"=>"Windows Vista", "value_percent"=>"2.1"}
]
operating_systems.map(&:values).to_h
# => {"iPhone"=>"42.6",
# "Windows 7"=>"21.3",
# "Android"=>"12.8",
# "Mac OS X"=>"8.5",
# "Windows 8.1"=>"6.4",
# "Windows XP"=>"4.3",
# "Linux"=>"2.1",
# "Windows Vista"=>"2.1"}
Which works on Ruby 2.1+.
Or, on older versions of Ruby:
Hash[operating_systems.map(&:values)]
# => {"iPhone"=>"42.6",
# "Windows 7"=>"21.3",
# "Android"=>"12.8",
# "Mac OS X"=>"8.5",
# "Windows 8.1"=>"6.4",
# "Windows XP"=>"4.3",
# "Linux"=>"2.1",
# "Windows Vista"=>"2.1"}
If folding the keys to lowercase is needed use these to replace the above commands:
operating_systems.map{ |h| k, v = h.values; [k.downcase, v] }.to_h
# => {"iphone"=>"42.6",
# "windows 7"=>"21.3",
# "android"=>"12.8",
# "mac os x"=>"8.5",
# "windows 8.1"=>"6.4",
# "windows xp"=>"4.3",
# "linux"=>"2.1",
# "windows vista"=>"2.1"}
Hash[operating_systems.map{ |h| k, v = h.values; [k.downcase, v] }]
# => {"iphone"=>"42.6",
# "windows 7"=>"21.3",
# "android"=>"12.8",
# "mac os x"=>"8.5",
# "windows 8.1"=>"6.4",
# "windows xp"=>"4.3",
# "linux"=>"2.1",
# "windows vista"=>"2.1"}
Upvotes: 1
Reputation: 36880
Here's one way
op_sys = [{"title"=>"iPhone", "value_percent"=>"42.6"}, {"title"=>"Windows 7", "value_percent"=>"21.3"}, {"title"=>"Android", "value_percent"=>"12.8"}, {"title"=>"Mac OS X", "value_percent"=>"8.5"}, {"title"=>"Windows 8.1", "value_percent"=>"6.4"}, {"title"=>"Windows XP", "value_percent"=>"4.3"}, {"title"=>"Linux", "value_percent"=>"2.1"}, {"title"=>"Windows Vista", "value_percent"=>"2.1"}]
new_hash = op_sys.inject({}) {|r,e| r[e['title']] = e['value_percent']; r}
p new_hash
EDIT
You may have wanted the new hash keys to be in downcase... so an alternative:
new_hash = op_sys.inject({}) {|r,e| r[e['title'].downcase] = e['value_percent']; r}
Upvotes: 2
Reputation: 168249
[
{"title"=>"iPhone", "value_percent"=>"42.6"},
{"title"=>"Windows 7", "value_percent"=>"21.3"},
{"title"=>"Android", "value_percent"=>"12.8"},
{"title"=>"Mac OS X", "value_percent"=>"8.5"},
{"title"=>"Windows 8.1", "value_percent"=>"6.4"},
{"title"=>"Windows XP", "value_percent"=>"4.3"},
{"title"=>"Linux", "value_percent"=>"2.1"},
{"title"=>"Windows Vista", "value_percent"=>"2.1"}
]
.map{|h| h.values.map(&:downcase)}.to_h
# =>
# {
# "iphone"=>"42.6",
# "windows 7"=>"21.3",
# "android"=>"12.8",
# "mac os x"=>"8.5",
# "windows 8.1"=>"6.4",
# "windows xp"=>"4.3",
# "linux"=>"2.1",
# "windows vista"=>"2.1"
# }
Upvotes: 6
Reputation: 9782
Combine Enumerable#reduce
with Hash#merge
op_sys.reduce({}) { |hsh, itx| hsh.merge({ itx["title"] => itx["value_percent"]}) }
=> {"iPhone"=>"42.6", "Windows 7"=>"21.3", "Android"=>"12.8", "Mac OS X"=>"8.5", "Windows 8.1"=>"6.4", "Windows XP"=>"4.3", "Linux"=>"2.1", "Windows Vista"=>"2.1"}
Upvotes: 0