47

How can I check whether one array is a subset of another array, regardless of the order of elements?

a1 = [3, 6, 4]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

...?

a1 is a subset of a2
5
  • Oh, which structure. Best is probably sets, since that's what sets are good at--but as the variety of answers shows (and there are yet more options), it may not matter--depending on your needs. Commented May 12, 2012 at 21:18
  • Can there be duplicates in a1 or a2? If there can be duplicates in a1, do there have to be the same number or more duplicates in a2? In other words, what should the result be if your variables have the values a1 = [1, 1] and a2 = [1,2,3,4,5,6,7,8,9]? Commented May 12, 2012 at 21:23
  • Currently I don't expect duplicates, but I imagine I would end up working with sets that contains duplicate values where I actually want to say "dupes don't matter". Would that cause an issue with arrays? Commented May 12, 2012 at 21:53
  • Possible duplicate of Ruby: Array contained in Array, any order Commented Sep 12, 2016 at 18:55
  • But the other way. Commented May 24, 2024 at 14:27

4 Answers 4

80

Easiest may be:

(a1 - a2).empty?
Sign up to request clarification or add additional context in comments.

3 Comments

This is pure ruby and does not need require "set"
set is stdlib, so it's arguable to say that it is less pure that using list differences.
This is the right answer, since it prevents initialization of new objects, and clogging of memory. Here only the intersect is created.
42

Use sets. Then you can use set.subset?. Example:

require 'set'

a1 = Set[3,6,4]
a2 = Set[1,2,3,4,5,6,7,8,9]

puts a1.subset?(a2)

Output:

true

See it working online: ideone

1 Comment

Another advantage of Set is that you can also check other properties, such as proper_subset? if you didn't want identical sets to return true.
35

The data structure you already have is perfect, just check the intersection:

(a1 & a2) == a1

Update: The comment discussing permutations is interesting and creative, but quite incorrect as the Ruby implementors anticipated this concern and specified that the order of the result is the order of a1. So this does work, and will continue to work in the future. (Arrays are ordered data structures, not sets. You can't just permute the order of an array operation.)

I do rather like Dave Newton's answer for coolness, but this answer also works, and like Dave's, is also core Ruby.

5 Comments

Oh, just take the intersection and check. Didn't think of that lol
I'm not certain if mine is really better, as it depends on the implemention being sort-stable. (Also on no duplicates, but the definition of the question as a set operation seems to imply that. I suppose one could sort both terms.)
I realize this answer is almost 4 years old, but this does not necessarily work. a1 & a2 will give a permutation of a1, which if the elements are not in the same order, will give false when comparing it == to a1. For example, a1=%w(a c); a2= %w(a b c); perm=a1&a2; (may give ['c','a']); perm==a1 => false. What is guaranteed to work is a1.permutation.include?(a1&a2).
@istrasci, the core docs specify at ruby-doc.org/core-2.3.1/Array.html#method-i-26 that The order is preserved from the original array. This does work correctly and will continue to do so in the future as this behavior is part of the specification of the & method on Array. It's therefore also not necessary to sort the result.
sorry, this method is wrong, it possible a1=[1,2,3];sub_a1=[2,1];(a1&sub_a1)==a1 equal false as it need sort first then compare.
3

Perhaps not fast, but quite readable

def subset?(a,b)
  a.all? {|x| b.include? x}
end

1 Comment

x.in? b also works with ActiveSupport. (stackoverflow.com/a/10601055/4960855)

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.