Search code examples
ruby-on-railsrubyruby-hash

Duplicate Hash Key unique Pair


I have a data pair:

[{:mobile=>21, :web=>43},{:mobile=>23, :web=>543},{:mobile=>23, :web=>430},{:mobile=>34, :web=>13},{:mobile=>26, :web=>893}]

How can I make this into:

[{mobile: [21, 23, 34, 26]}, {web: [43, 543, 430, 13, 893]}

Solution

  • When I look at the provide scenario I see the following solution:

    data = [{:mobile=>21, :web=>43},{:mobile=>23, :web=>543},{:mobile=>23, :web=>430},{:mobile=>34, :web=>13},{:mobile=>26, :web=>893}]
    keys = [:mobile, :web]
    result = keys.zip(data.map { |hash| hash.values_at(*keys) }.transpose).to_h
    #=> {:mobile=>[21, 23, 23, 34, 26], :web=>[43, 543, 430, 13, 893]}
    

    This first extracts the values of the keys from each hash, then transposes the the resulting array. This changes [[21, 43], [23, 543], [23, 430], ...] into [[21, 23, 23, ...], [43, 543, 430, ...]]. This result can be zipped back to the keys and converted into a hash.

    To get rid of duplicates you could add .each(&:uniq!) after the transpose call, or map the collections to a set .map(&:to_set) (you need to require 'set') if you don't mind the values being sets instead of arrays.

    result = keys.zip(data.map { |hash| hash.values_at(*keys) }.transpose.each(&:uniq!)).to_h
    #=> {:mobile=>[21, 23, 34, 26], :web=>[43, 543, 430, 13, 893]}
    
    require 'set'
    result = keys.zip(data.map { |hash| hash.values_at(*keys) }.transpose.map(&:to_set)).to_h
    #=> {:mobile=>#<Set: {21, 23, 34, 26}>, :web=>#<Set: {43, 543, 430, 13, 893}>}
    

    References: