Reputation: 990
The question is, given [1,2,3,4,5]
and [2,4,5]
, to determine whether (every element in) the second array is contained in the first one. The answer is true.
What's the most succinct and efficient way to do better than:
arr2.reject { |e| arr1.include?(e) } .empty?
Upvotes: 0
Views: 98
Reputation: 9497
As mentioned by @Ryan you can use sets. In which case Set#subset?
is available to you which is pretty readable (note the two different ways of defining a set from an array):
require 'set'
s1 = Set.new([1, 2, 3])
s2 = [1, 2].to_set
s3 = [1, 3].to_set
s4 = [1, 4].to_set
s1.subset? s1 #=> true
s2.subset? s1 #=> true
s3.subset? s1 #=> true
s4.subset? s1 #=> false
Also consider using Set#proper_subset
if required.
s1.proper_subset? s1 #=> false
s2.proper_subset? s1 #=> true
NB A set contains no duplicate elements e.g. Set.new([1,2,3,3]) #=> #<Set: {1, 2, 3}>
Upvotes: 1
Reputation: 1957
Array subtraction should work, as in
(arr2 - arr1).empty?
Description of method:
Returns a new array that is a copy of the original array, removing any items that also appear in [the second array]. The order is preserved from the original array.
It compares elements using their hash and eql? methods for efficiency.
I don't consider myself an expert on efficiency, but @Ryan indicated in comments to his answer that it's reasonably efficient at scale.
Upvotes: 4
Reputation: 224857
The bad O(n²) one-liner would look like this:
arr2.all? { |x| arr1.include? x }
arr2.all? &arr1.method(:include?) # alternative
If your objects are hashable, you can make this O(n) by making a set out of the first array:
require 'set'
arr2.all? &Set.new(arr1).method(:include?)
If your objects are totally, like, ordered, you can make it O(n log n) with a sort and a binary search:
arr1.sort!
arr2.all? { |x| arr1.bsearch { |y| x <=> y } }
Upvotes: 3