如何确定一个数组是否包含另一个数组的所有元素

鉴于:

a1 = [5, 1, 6, 14, 2, 8] 

我想确定它是否包含所有元素:

 a2 = [2, 6, 15] 

在这种情况下,结果是false

有没有内置的Ruby / Rails方法来识别这种数组包含?

实现这一点的一个方法是:

 a2.index{ |x| !a1.include?(x) }.nil? 

有更好的,更可读的方法吗?

 a = [5, 1, 6, 14, 2, 8] b = [2, 6, 15] a - b => [5, 1, 14, 8] b - a => [15] (b - a).empty? => false 

也许这更容易阅读:

 a2.all? { |e| a1.include?(e) } 

你也可以使用数组相交:

 (a1 & a2).size == a1.size 

请注意,这里只是为了速度而使用size ,你也可以做(较慢):

 (a1 & a2) == a1 

但我想第一个更可读。 这3个是简单的ruby(不是导轨)。

这可以通过做

 (a2 & a1) == a2 

这将创build两个数组的交集,返回a1所有元素,这些元素也位于a1 。 如果结果与a2相同,则可以确定您具有包含在a1所有元素。

这种方法只有在a2中的所有元素都彼此不同的情况下才起作用。 如果有双打,这种方法失败。 Tempos的那个仍然有效,所以我全心全意推荐他的方法(也可能更快)。

如果没有重复的元素,或者你不关心它们,那么你可以使用Set类:

 a1 = Set.new [5, 1, 6, 14, 2, 8] a2 = Set.new [2, 6, 15] a1.subset?(a2) => false 

这在幕后使用

 all? { |o| set.include?(o) } 

根据数组的大小,你可以考虑一个有效的algorithmO(n log n)

 def equal_a(a1, a2) a1sorted = a1.sort a2sorted = a2.sort return false if a1.length != a2.length 0.upto(a1.length - 1) do |i| return false if a1sorted[i] != a2sorted[i] end end 

对成本O(n log n)进行sorting并检查每对成本O(n),因此该algorithm是O(n log n)。 其他algorithm不能更快(渐近地)使用未sorting的数组。

你可以猴子修改Array类:

 class Array def contains_all?(ary) ary.uniq.all? { |x| count(x) >= ary.count(x) } end end 

testing

 irb(main):131:0> %w[abcc].contains_all? %w[abc] => true irb(main):132:0> %w[abcc].contains_all? %w[abcc] => true irb(main):133:0> %w[abcc].contains_all? %w[abccc] => false irb(main):134:0> %w[abcc].contains_all? %w[a] => true irb(main):135:0> %w[abcc].contains_all? %w[x] => false irb(main):136:0> %w[abcc].contains_all? %w[] => true irb(main):137:0> %w[abcd].contains_all? %w[dch] => false irb(main):138:0> %w[abcd].contains_all? %w[dbc] => true 

当然,这个方法可以写成一个标准的方法,例如

 def contains_all?(a,b) b.uniq.all? { |x| a.count(x) >= b.count(x) } end 

你可以像调用它

 contains_all?(%w[abcc], %w[ccc]) 

事实上,在分析之后,以下版本要快得多,代码也更短。

 def contains_all?(a,b) b.all? { |x| a.count(x) >= b.count(x) } end