Reputation: 1751
I am trying to convert an array into a hash by iterating through it. I have the following array:
weekdays = [["Monday",2],["Tuesday",4],["Thursday",5]]
I'm looping through the array to create a hash like so:
hash_weekdays = Hash.new
weekdays.each do |item|
hash_weekdays["weekday"] = item[0]
hash_weekdays["number"] = item[1]
end
This, however, only shows me the last weekday. Any ideas on where to go from here? Thanks!
Upvotes: 0
Views: 856
Reputation: 110755
You need to change your code to the following:
hash_weekdays = Hash.new
weekdays.each do |item|
hash_weekdays[item[0]] = item[1]
end
hash_weekdays
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
When the first element of weekdays
(["Monday",2]
) is passed to the block, the block variable is assigned its value:
item = ["Monday",2]
Since you need to reference each element of item
, it's common to use two block variables whose values are assigned using parallel assignment (aka multiple assignment):
day, nbr = ["Monday",2]
#=> ["Monday", 2]
day #=> "Monday"
nbr #=> 2
This allows you to write
hash_weekdays = {} # the more common way of writing hash_weekdays = Hash.new
weekdays.each { |day, nbr| hash_weekdays[day] = nbr } # used {...} rather than do..end
hash_weekdays
which is arguably clearer.
Notice that you first initialize hash_weekdays
to an empty hash, then need the line hash_weekdays
at the end if you wish to obtain the new value of the hash (as the last line of a method, for example). You can reduce this to a single line (very Ruby-like) by using the method Enumerable#each_with_object:
weekdays.each_with_object({}) { |item, hash_weekdays| hash_weekdays[item[0]] = item[1] }
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
Notice this uses parallel assignment. The first element passed to the block, [["Monday", 2], {}]
, is assigned as follows:
item, hash_weekdays = weekdays.each_with_object({}).next
#=> [["Monday", 2], {}]
item
#=> ["Monday", 2]
hash_weekdays
#=> {}
The Ruby way is to use parallel assignment in a slightly more complex way:
weekdays.each_with_object({}) { |(day, nbr), hash_weekdays|
hash_weekdays[day] = nbr }
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
As others have noted, the most straightforward answer is to use the method Hash::[] or (introduced in v2.0) Array#to_h:
Hash[weekdays]
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
Hash[*weekdays.flatten] #=> Hash["Monday", 2, "Tuesday", 4, "Thursday", 5]
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
weekdays.to_h
#=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
Upvotes: 1
Reputation: 3320
A hash holds key-value pairs. Each key references one value only and each key is uniq in a hash. The values of your keys weekday
and number
will be overwritten with each iteration. That's the reason why you get the result of the last iteration only.
You could convert it to an array of hashes as an alternative.
weekdays.map{|day, number| {weekday:day, number: number}}
# => [{:weekday=>"Monday", :number=>2}, {:weekday=>"Tuesday", :number=>4}, {:weekday=>"Thursday", :number=>5}]
If your weekdays or numbers are unique in your main array you could use one kind of them as key and the other as value in a hash.
weekdays.to_h
# => {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
or
weekdays.to_h.invert
# => {2=>"Monday", 4=>"Tuesday", 5=>"Thursday"}
Upvotes: 1
Reputation: 9508
You could do this instead:
weekdays.to_h #=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
or fixing your code:
weekdays = [["Monday",2],["Tuesday",4],["Thursday",5]]
hash_weekdays = Hash.new
weekdays.each do |item|
hash_weekdays[item[0]] = item[1]
end
p hash_weekdays #=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}
Upvotes: 1