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

时间:2011-09-12 12:34:13

标签: ruby-on-rails arrays ruby

假设:

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

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

a2 = [2, 6, 15]

在这种情况下,结果为false

是否有任何内置的Ruby / Rails方法来识别这种数组包含?

实现这一目标的一种方法是:

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

是否有更好,更易读的方式?

8 个答案:

答案 0 :(得分:283)

a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
=> [5, 1, 14, 8]

b - a
=> [15]

(b - a).empty?
=> false

答案 1 :(得分:69)

也许这更容易阅读:

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

您也可以使用数组交集:

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

请注意,size仅用于速度,您也可以(慢):

(a1 & a2) == a1

但我想第一个更具可读性。这3个是普通的红宝石(不是铁轨)。

答案 2 :(得分:52)

这可以通过

来实现
(a2 & a1) == a2

这将创建两个数组的交集,返回a2中同样位于a1的所有元素。如果结果与a2相同,则可以确保a1中包含所有元素。

此方法仅在a2中的所有元素首先彼此不同时才有效。如果有双打,这种方法就失败了。那时来自Tempos的人仍然有效,所以我全心全意地推荐他的方法(也可能更快)。

答案 3 :(得分:10)

如果没有重复元素或您不关心它们,那么您可以使用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) }

答案 4 :(得分:1)

你可以修补Array类:

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

测试

irb(main):131:0> %w[a b c c].contains_all? %w[a b c]
=> true
irb(main):132:0> %w[a b c c].contains_all? %w[a b c c]
=> true
irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c]
=> false
irb(main):134:0> %w[a b c c].contains_all? %w[a]
=> true
irb(main):135:0> %w[a b c c].contains_all? %w[x]
=> false
irb(main):136:0> %w[a b c c].contains_all? %w[]
=> true
irb(main):137:0> %w[a b c d].contains_all? %w[d c h]
=> false
irb(main):138:0> %w[a b c d].contains_all? %w[d b c]
=> true

当然,该方法可以作为单独的标准方法编写,例如

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

你可以像

一样调用它
contains_all?(%w[a b c c], %w[c c c])

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

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

答案 5 :(得分:0)

根据数组的大小,您可以考虑使用有效的算法O(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)进行排序并检查每对成本为O(n),因此该算法为O(n log n)。其他算法使用未排序的数组不能更快(渐近)。

答案 6 :(得分:0)

如果任一数组中都有重复的元素,则基于(a1-a2)或(a1&a2)的大多数答案将不起作用。我到达这里是为了寻找一种方法来查看一个单词的所有字母(拆分为一个数组)是否是一组字母的一部分(例如,拼字游戏)。这些答案都不起作用,但是这个答案可以做到:

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end

答案 7 :(得分:0)

当我试图查找一个数组 ["a", "b", "c"] 是否包含另一个数组 ["a", "b"] 时,我被定向到这篇文章,在我的情况下,相同的顺序 是该问题的附加要求.

这是我的解决方案(我相信它的复杂度为 O(n)),适用于有额外要求的任何人:

def array_includes_array(array_to_inspect, array_to_search_for)
  inspectLength = array_to_inspect.length
  searchLength = array_to_search_for.length

  if searchLength == 0 then
    return true
  end

  if searchLength > inspectLength then
    return false
  end

  buffer = []

  for i in 0..inspectLength
    buffer.push(array_to_inspect[i])

    bufferLastIndex = buffer.length - 1
    if(buffer[bufferLastIndex] != array_to_search_for[bufferLastIndex]) then
      buffer.clear
      next
    end

    if(buffer.length == searchLength) then
      return true
    end
  end

  return false
end

这会产生测试结果:

puts "1: #{array_includes_array(["a", "b", "c"], ["b", "c"])}" # true
puts "2: #{array_includes_array(["a", "b", "c"], ["a", "b"])}" # true
puts "3: #{array_includes_array(["a", "b", "c"], ["b", "b"])}" # false
puts "4: #{array_includes_array(["a", "b", "c"], ["c", "b", "a"])}" # false
puts "5: #{array_includes_array(["a", "b", "c"], [])}" # true
puts "6: #{array_includes_array([], ["a"])}" # false
puts "7: #{array_includes_array([], [])}" # true