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}]
source to share
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.
source to share