考虑到:

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

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

a2 = [2, 6, 15]

在这种情况下,结果是假的。

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

实现它的一种方法是:

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

有没有更好的、可读性更强的方法?


当前回答

也许下面这个更容易理解:

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

你也可以使用数组交集:

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

注意,这里使用的大小只是为了速度,你也可以这样(更慢):

(a1 & a2) == a1

但我想第一个更有可读性。这三个是普通的ruby(不是rails)。

其他回答

也许下面这个更容易理解:

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

你也可以使用数组交集:

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

注意,这里使用的大小只是为了速度,你也可以这样(更慢):

(a1 & a2) == a1

但我想第一个更有可读性。这三个是普通的ruby(不是rails)。

当我试图找出一个数组["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

大多数基于(a1 - a2)或(a1 & a2)的答案,如果两个数组中都有重复的元素,就不能工作。我来到这里寻找一种方法来查看一个单词的所有字母(分割为一个数组)是否是一组字母的一部分(例如scrabble)。这些答案都没用,但这个答案有用:

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

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

b - a
# => [15]

(b - a).empty?
# => false

你可以给Array类打些小补丁:

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

test

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