code_aks
code_aks

Reputation: 2074

How to change array of arrays into hashmap?

I stuck in a situation, I have an array of array structure how can I make it hash like below:-

Example:

[[378, 1], [144, 1], [144, 1], [144, 3], [144, 7], [144, 6], [144, 8], [144, 8], [809, 1], [809, 1], [809, 8]]  

Convert to:

{378=>[1], 144=>[1,3,7,6,8], 809=>[1,8]}

means take the first element as key and make the second element in another array as value matched to key.

I tried below method but failed in one use case:

raw_hash = arr.group_by { |sub_arr| sub_arr[0] }
modified_hash = {}
raw_hash.each do |k, arr|
   modified_hash[k] = [ arr.flatten.uniq - [ k ] ].flatten
end

failed use-case is if first element and second element both will same then it will make unique and subtract second value

Upvotes: 0

Views: 148

Answers (2)

Ilya
Ilya

Reputation: 13477

Just use each_with_object, it is faster and consumes less memory than @mrzasa's approach:

array.each_with_object(Hash.new { |h, k| h[k] = [] }) do |(first, last), m|  
  m[first] |= [last]
end
#=> {378=>[1], 144=>[1, 3, 7, 6, 8], 809=>[1, 8]}

But for the uniqueness the simplest probably would be using Set:

array.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |(first, last), m|  
  m[first] << last 
end
#=> {378=>#<Set: {1}>, 144=>#<Set: {1, 3, 7, 6, 8}>, 809=>#<Set: {1, 8}>}

Upvotes: 4

mrzasa
mrzasa

Reputation: 23307

Group by the first element of the array and then chose the last second elements of the grouped values.

a = [[378, 1], [144, 1], [144, 1], [144, 3], [144, 7], [144, 6], [144, 8], [144, 8], [809, 1], [809, 1], [809, 8]] 
a.group_by(&:first).map{|k, v| [k, v.map(&:last)]}.to_h
# => {378=>[1], 144=>[1, 1, 3, 7, 6, 8, 8], 809=>[1, 1, 8]}

EDIT:

If you want to have a unique values, add uniq to the map that collects them:

a.group_by(&:first).map{|k, v| [k, v.map(&:last).uniq]}.to_h
#=> {378=>[1], 144=>[1, 3, 7, 6, 8], 809=>[1, 8]}

Upvotes: 3

Related Questions