dmt2989
dmt2989

Reputation: 1620

Ruby- creating an hash from an array of hashes

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

Answers (5)

user2864740
user2864740

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

the Tin Man
the Tin Man

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

SteveTurczyn
SteveTurczyn

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

sawa
sawa

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

bjhaid
bjhaid

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

Related Questions