0

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?
1
  • 2
    What is the expectation if arrays have duplicate items? Commented Apr 3, 2017 at 3:15

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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 } }

9 Comments

If you use Set, then why not: Set.new(arr2) <= Set.new(arr1)
@Tao: Builds a second set for no time benefit, but if you like how it reads that’s important too.
I think... if you're using sets you can write: arr1 & arr2 == arr2 as well.
@sagarpandya82: Yep, nice one.
@sagarpandya82 oh, yes, that's actually what I was looking for. Thanks!
|
1

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}>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.