Reputation: 2074
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
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
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