Nicolae Rotaru
Nicolae Rotaru

Reputation: 189

Array of arrays into array of hashes

i want to convert in ruby

[[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]

into

[{1=>1}, {2=>3}, {3=>5}, {4=>1}, {1=>2}, {2=>3}, {3=>5}, {4=>1}]

and after this to obtain sum of all different keys:

{1=>3,2=>6,3=>10,4=>2}

Upvotes: 1

Views: 168

Answers (4)

tokland
tokland

Reputation: 67850

Functional approach:

xs = [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]    
Hash[xs.group_by(&:first).map do |k, pairs| 
  [k, pairs.map { |x, y| y }.inject(:+)]
end]
#=> {1=>3, 2=>6, 3=>10, 4=>2}

Using Facets is much simpler thanks to the abstractions map_by (a variation of group_by) and mash (map + Hash):

require 'facets'
xs.map_by { |k, v| [k, v] }.mash { |k, vs| [k, vs.inject(:+)] }
#=> {1=>3, 2=>6, 3=>10, 4=>2}

Upvotes: 2

Pritesh Jain
Pritesh Jain

Reputation: 9146

arr= [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]

final = Hash.new(0)

second_step = arr.inject([]) do |arr,inner|
   arr << Hash[*inner]
   final[inner.first] += inner.last
   arr
end

second_step
#=> [{1=>1}, {2=>3}, {3=>5}, {4=>1}, {1=>2}, {2=>3}, {3=>5}, {4=>1}] 
final
#=> {1=>3, 2=>6, 3=>10, 4=>2}

if you directly only need the last step

arr.inject(Hash.new(0)){|hash,inner| hash[inner.first] += inner.last;hash}
=> {1=>3, 2=>6, 3=>10, 4=>2} 

Upvotes: 0

sawa
sawa

Reputation: 168081

For the second question

sum = Hash.new(0)
original_array.each{|x, y| sum[x] += y}
sum # => {1 => 3, 2 => 6, 3 => 10, 4 => 2}

Upvotes: 2

Joshua Cheek
Joshua Cheek

Reputation: 31726

You don't need the intermediate form.

arrays = [[1, 1], [2, 3], [3, 5], [4, 1], [1, 2], [2, 3], [3, 5], [4, 1]]

aggregate = arrays.each_with_object Hash.new do |(key, value), hash|
  hash[key] = hash.fetch(key, 0) + value
end

aggregate # => {1=>3, 2=>6, 3=>10, 4=>2}

Upvotes: 1

Related Questions