Reputation: 1473
I want to find all elements that are the same between two arrays, including elements that are repeated multiple times in both arrays. For instance, I want
[1,1,1,2]
and
[1,1,3,4]
to give
[1,1]
I could iterate through the array and keep track of it, but I was wondering if there were a more ruby way of doing this.
Upvotes: 0
Views: 77
Reputation: 110675
a = [1,1,1,2,5]
b = [1,1,3,2,4,2]
def counting_hash(arr)
arr.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
end
hb = counting_hash(b)
#=> {1=>2, 3=>1, 2=>2, 4=>1}
counting_hash(a).each_with_object([]) do |(k,v),a|
n = [v, hb[k]].min
n.times { a << k } if n > 0
end
#=> [1, 1, 2]
Note that
counting_hash(a)
#=> {1=>3, 2=>1, 5=>1}
and
hb[5]
#=> 0
as hb
has a default value of zero.
Upvotes: 1
Reputation: 369458
It looks like you want multiset-intersection. There is no multiset datastructure in the Ruby core lib or stdlib, but there are multiple implementations you can find on the web. I'll just randomly pick one (it doesn't really matter, multiset is a mathematical concept with strict definition, all implementations behave more or less the same):
require 'multiset'
ms = Multiset[1, 1, 1, 2] & Multiset[1, 1, 3, 4]
#=> #<Multiset:#2 1>
ms.to_a
#=> [1, 1]
If you must, you can convert it to an array using Multiset#to_a
, but remember: most of the interesting methods you can call on Array
are actually from the Enumerable
mixin and thus available to all collections; you often don't actually need to have an array.
Upvotes: 5