I have an array like this
arr = [ { name: "Josh", grade: 90 }, {name: "Josh", grade: 70 },
{ name: "Kevin", grade: 100 }, { name: "Kevin", grade: 95 },
{ name: "Ben", grade: 90 }, { name: "Rod", grade: 90 },
{ name: "Rod", grade: 70 }, { name: "Jack", grade: 60 } ]
I would like Ben and Jack to be removed since they only have one record in this array. What would be the most elegant way to get this done? I could manually go through it and check, but is there a better way? Like the opposite of
arr.uniq! { |person| person[:name] }
arr.reject! { |x| arr.count { |y| y[:name] == x[:name] } == 1 }
An O(n)
solution:
count_hash = {}
arr.each { |x| count_hash[x[:name]] ||= 0; count_hash[x[:name]] += 1 }
arr.reject! { |x| count_hash[x[:name]] == 1 }
Here are three more ways that might be of some interest, though I prefer Robert's solution.
Each of the following returns:
#=> [{:name=>"Josh" , :grade=> 90}, {:name=>"Josh" , :grade=>70},
# {:name=>"Kevin", :grade=>100}, {:name=>"Kevin", :grade=>95},
# {:name=>"Rod" , :grade=> 90}, {:name=>"Rod" , :grade=>70}]
#1
Use the well-worn but dependable Enumerable#group_by to aggregate by name, Hash#values to extract the values then reject those that appear but once:
arr.group_by { |h| h[:name] }.values.reject { |a| a.size == 1 }.flatten
#2
Use the class method Hash#new with a default of zero to identify names with multiple entries, then select for those:
multiples = arr.each_with_object(Hash.new(0)) { |h,g| g[h[:name]] += 1 }
.reject { |_,v| v == 1 } #=> {"Josh"=>2, "Kevin"=>2, "Rod"=>2}
arr.select { |h| multiples.key?(h[:name]) }
#3
Use the form of Hash#update (aka Hash#merge!
) that takes a block to determine names that appear only once, then reject for those:
singles = arr.each_with_object({}) { |h,g|
g.update({ h[:name] => 1 }) { |_,o,n| o+n } }
.select { |_,v| v == 1 } #=> {"Ben"=>1, "Jack"=>1}
arr.reject { |h| singles.key?(h[:name]) }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.