Mr H
Mr H

Reputation: 5304

How to create hash from array

Here is my array:

sorted_array = [["Friday", "42", 8], ["Friday", "34", 8], ["Friday", "41", 78], ["Friday", "35", 7], ["Friday", "40", 7], ["Friday", "36", 6], ["Friday", "39", 7], ["Friday", "37", 56], ["Friday", "38", 6], ["Monday", "38", 3], ["Monday", "39", 5], ["Monday", "37", 54], ["Monday", "40", 6], ["Monday", "36", 6], ["Monday", "41", 7], ["Monday", "35", 7], ["Monday", "42", 7], ["Monday", "34", 8]]

I need to make:

{ 'Friday' => [ ["42", 8], ["34", 8], ["41", 78], ["35", 7], [ "40", 7], ["36", 6], [ "39", 7], ["37", 56], [ "38", 6] ]  }

The same with "Monday".Can someone shed a light on this?

This is how I get the data from POST:

{"0"=>{"Monday"=>{"34"=>8}, "Friday"=>{"34"=>8}}, "1"=>{"Monday"=>{"35"=>7}, "Friday"=>{"35"=>7}}, "2"=>{"Monday"=>{"36"=>6}, "Friday"=>{"36"=>6}}, "3"=>{"Monday"=>{"37"=>54}, "Friday"=>{"37"=>56}}, "4"=>{"Monday"=>{"38"=>3}, "Friday"=>{"38"=>6}}, "5"=>{"Monday"=>{"39"=>5}, "Friday"=>{"39"=>7}}, "6"=>{"Monday"=>{"40"=>6}, "Friday"=>{"40"=>7}}, "7"=>{"Monday"=>{"41"=>7}, "Friday"=>{"41"=>78}}, "8"=>{"Monday"=>{"42"=>7}, "Friday"=>{"42"=>8}}}

Then I turn it into array and sorted:

 hash_array = []
 specific_ranges.each do |key, value|
   value.each do |day, scores|
      scores.each do |a_score, amount|
         hash_array.push [day, a_score, amount]
      end
   end
 end

Sorted:

sorted_array = hash_array.sort_by &:first

Upvotes: 1

Views: 101

Answers (7)

hirolau
hirolau

Reputation: 13901

Ruby MAGIC:

p sorted_array.group_by(&:shift) #=> {"Friday"=>[["42", 8], ["34", 8], ["41", 78], ["35", 7] ...

Explanation: shift gets the first value of the array and at the same time removes it from the array, so the group_by function produce exactly what you are looking for.

Upvotes: 5

Cary Swoveland
Cary Swoveland

Reputation: 110675

Two for the price of one:

#1

arr.each_with_object({}) { |a,h| h.update(a.shift=>[a]) { |_,o,n| o+n } }

#2

h = arr.group_by(&:first)
h.each { |k,v| h[k] = v.transpose[1..-1].transpose }

Upvotes: 0

sawa
sawa

Reputation: 168081

h = sorted_array.group_by(&:first).each_value{|a| a.each(&:shift)}

h.select{|k, _| k == "Friday"}
#=> { 'Friday' => [ ["42", 8], ["34", 8], ["41", 78], ["35", 7], [ "40", 7], ["36", 6], [ "39", 7], ["37", 56], [ "38", 6] ]  }

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

This is a standard task for Array#reduce.

sorted_array.reduce({}) { |memo, e| 
  (memo[e.first] ||= []) << e[1..-1]
  memo 
}

Here we fulfill the hash with the rest of every array element, using first elements as keys.

UPD Actually, you don’t need to reorganize your hash, everything might be done within one step:

h = {"0"=>{"Monday"=>{"34"=>8}, "Friday"=>{"34"=>8}}, "1"=>{"Monday"=>{"35"=>7}, "Friday"=>{"35"=>7}}, "2"=>{"Monday"=>{"36"=>6}, "Friday"=>{"36"=>6}}, "3"=>{"Monday"=>{"37"=>54}, "Friday"=>{"37"=>56}}, "4"=>{"Monday"=>{"38"=>3}, "Friday"=>{"38"=>6}}, "5"=>{"Monday"=>{"39"=>5}, "Friday"=>{"39"=>7}}, "6"=>{"Monday"=>{"40"=>6}, "Friday"=>{"40"=>7}}, "7"=>{"Monday"=>{"41"=>7}, "Friday"=>{"41"=>78}}, "8"=>{"Monday"=>{"42"=>7}, "Friday"=>{"42"=>8}}}
h.reduce({}) { |memo, k| 
  k.last.each { |k,v| (memo[k] ||= []) << v.to_a.flatten }
  memo 
}

Upvotes: 0

shivam
shivam

Reputation: 16506

you can try something like this directly to your data:

data = {"0"=>{"Monday"=>{"34"=>8}, "Friday"=>{"34"=>8}}, "1"=>{"Monday"=>{"35"=>7}, "Friday"=>{"35"=>7}}, "2"=>{"Monday"=>{"36"=>6}, "Friday"=>{"36"=>6}}, "3"=>{"Monday"=>{"37"=>54}, "Friday"=>{"37"=>56}}, "4"=>{"Monday"=>{"38"=>3}, "Friday"=>{"38"=>6}}, "5"=>{"Monday"=>{"39"=>5}, "Friday"=>{"39"=>7}}, "6"=>{"Monday"=>{"40"=>6}, "Friday"=>{"40"=>7}}, "7"=>{"Monday"=>{"41"=>7}, "Friday"=>{"41"=>78}}, "8"=>{"Monday"=>{"42"=>7}, "Friday"=>{"42"=>8}}}

a ||= Hash.new { |h, k| h[k] = [] }   
data.each{ |d|
  d[1].keys.each { |key|
    a[key] << d[1][key]
  }
}

a
# => {"Monday"=>[{"34"=>8}, {"35"=>7}, {"36"=>6}, {"37"=>54}, {"38"=>3}, {"39"=>5}, {"40"=>6}, {"41"=>7}, {"42"=>7}], "Friday"=>[{"34"=>8}, {"35"=>7}, {"36"=>6}, {"37"=>56}, {"38"=>6}, {"39"=>7}, {"40"=>7}, {"41"=>78}, {"42"=>8}]}

You can improve the result further by using Array#uniq for array of hashes if required.

Upvotes: 2

Santhosh
Santhosh

Reputation: 29114

 sorted_array.group_by(&:first).map { |k, v| [k, v.map { |a| a[1..-1] }] }.to_h
 # {"Friday"=>[["42", 8], ["34", 8], ["41", 78], ["35", 7], ["40", 7], ["36", 6], ["39", 7], ["37", 56], ["38", 6]],
 #  "Monday"=>[["38", 3], ["39", 5], ["37", 54], ["40", 6], ["36", 6], ["41", 7], ["35", 7], ["42", 7], ["34", 8]]} 

Upvotes: 1

Deepesh
Deepesh

Reputation: 6398

I have a quick solution for you. This may not be the optimal but here it is:

sorted_array = [["Friday", "42", 8], ["Friday", "34", 8], ["Friday", "41", 78], ["Friday", "35", 7], ["Friday", "40", 7], ["Friday", "36", 6], ["Friday", "39", 7], ["Friday", "37", 56], ["Friday", "38", 6], ["Monday", "38", 3], ["Monday", "39", 5], ["Monday", "37", 54], ["Monday", "40", 6], ["Monday", "36", 6], ["Monday", "41", 7], ["Monday", "35", 7], ["Monday", "42", 7], ["Monday", "34", 8]]

s = sorted_array.select{|x| x[0] == 'Friday'}.each{|a| a.shift}

Hash['Friday', s]

This will return the result as you require. But while doing it I found a limitation that the line of code:

s = sorted_array.select{|x| x[0] == 'Friday'}.each{|a| a.shift}

is running just a single time and it will return a blank array if you run it the second time consecutively. So if you use this please take care of that. Hope this helps.

Upvotes: 0

Related Questions