1}, {:a => "90-bbb",:b => 89}...">

Get a unique element based on a string from an array of hashes

I have an array of hashes:

[{:a => "63-aaa",:b =>1}, {:a => "90-bbb",:b => 89}, {:a => "63-aaa", :b => 1},{:a => "45-hhh", :b => 44}, {:a => "32-kkk", :b => 67}, {: => "90-bbb", :b => 89}]

      

Key

a

It has a value of 63-aaa

, 90-bbb

, 45-hhh

and 32-kkk

. I want to get unique elements of an array based on value IDs a

like:

[{:a => "63-aaa",:b =>1}, {:a => "90-bbb",:b => 89}, {:a => "45-hhh", :b => 44}, {:a => "32-kkk", :b => 67}]

      

+3


source to share


2 answers


In this case, you can pass the block Array#uniq

:



arr.uniq { |hash| hash[:a] }

      

+8


source


It doesn't seem to you that one of each set of duplicates is being stored. Array#uniq

, with a block, is for this. It will contain the one with the lowest index. If you want the one with the highest index, just apply Array#reverse

before and after uniq

.

If, however, you wanted to use different information in each hash to determine which one to store, you can do so using the Update Hash # (aka merge!

) form , which takes a block:

arr = [{:a=>"63-aaa", :b=> 1}, {:a=>"90-bbb", :b=>89}, {:a=>"63-aaa", :b=>22},
       {:a=>"45-hhh", :b=>44}, {:a=>"32-kkk", :b=>67}, {:a=>"90-bbb", :b=>14}]

arr.each_with_object({}) do |g,h|
  h.update({ g[:a]=>g }) { |k,oh,nh| <code to return oh or nh> }
end.values

      

For example, suppose you want to store the hash h

for which h[:b]

is the largest:

arr.each_with_object({}) do |g,h|
  h.update({ g[:a]=>g }) { |k,oh,nh| nh[:b] > oh[:b] ? nh : oh }
end.values
  #=> [{:a=>"63-aaa", :b=>22}, {:a=>"90-bbb", :b=>89},
  #    {:a=>"45-hhh", :b=>44}, {:a=>"32-kkk", :b=>67}]

      

I created an empty hash (block variable h

) and then for each hash g

in, arr

update with a h

hash f = { g[:a]=>g }

. If both h

u f

have a key g[:a]

, block

{ |k,oh,nh| (nh[:b] > oh[:b]) ? nh : oh  }

      

it is proposed to determine the value of the key g[:a]

in h

(that is, which of the two hashes to store). Block variables:

k  = g[:a]
oh = h[g[:a]]
nh = g

      



(Note that k

it is not used in a block, so we can write block variables as |_,oh,nh|

.)

each_with_object

returns

h = {"63-aaa"=>{:a=>"63-aaa", :b=>22}, "90-bbb"=>{:a=>"90-bbb", :b=>89},
     "45-hhh"=>{:a=>"45-hhh", :b=>44}, "32-kkk"=>{:a=>"32-kkk", :b=>67}}

      

so we just need to extract the values:

h.values
  #=> [{:a=>"63-aaa", :b=>22}, {:a=>"90-bbb", :b=>89},
  #    {:a=>"45-hhh", :b=>44}, {:a=>"32-kkk", :b=>67}]

      

Another way, first run:

arr.group_by { |h| h[:a] }.values
  #=> [[{:a=>"63-aaa", :b=> 1}, {:a=>"63-aaa", :b=>22}],
  #    [{:a=>"90-bbb", :b=>89}, {:a=>"90-bbb", :b=>14}],
  #    [{:a=>"45-hhh", :b=>44}],
  #    [{:a=>"32-kkk", :b=>67}]]

      

and then use whatever criteria you would like to select one hash from each of the four arrays.

+2


source







All Articles