考虑到:
a1 = [5, 1, 6, 14, 2, 8]
我想确定它是否包含所有的元素:
a2 = [2, 6, 15]
在这种情况下,结果是假的。
是否有任何内置的Ruby/Rails方法来识别这样的数组包含?
实现它的一种方法是:
a2.index{ |x| !a1.include?(x) }.nil?
有没有更好的、可读性更强的方法?
考虑到:
a1 = [5, 1, 6, 14, 2, 8]
我想确定它是否包含所有的元素:
a2 = [2, 6, 15]
在这种情况下,结果是假的。
是否有任何内置的Ruby/Rails方法来识别这样的数组包含?
实现它的一种方法是:
a2.index{ |x| !a1.include?(x) }.nil?
有没有更好的、可读性更强的方法?
当前回答
这可以通过做来实现
(a2 & a1) == a2
这将创建两个数组的交集,返回a2中同样在a1中的所有元素。如果结果与a2相同,则可以确定a1中包含了所有元素。
这种方法只适用于a2中的所有元素都不同的情况。如果存在双精度,则此方法失败。Tempos的方法仍然有效,所以我全心全意地推荐他的方法(而且它可能更快)。
其他回答
大多数基于(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
你可以给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
如果没有重复的元素或者你不关心它们,那么你可以使用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) }
这可以通过做来实现
(a2 & a1) == a2
这将创建两个数组的交集,返回a2中同样在a1中的所有元素。如果结果与a2相同,则可以确定a1中包含了所有元素。
这种方法只适用于a2中的所有元素都不同的情况。如果存在双精度,则此方法失败。Tempos的方法仍然有效,所以我全心全意地推荐他的方法(而且它可能更快)。
也许下面这个更容易理解:
a2.all? { |e| a1.include?(e) }
你也可以使用数组交集:
(a1 & a2).size == a1.size
注意,这里使用的大小只是为了速度,你也可以这样(更慢):
(a1 & a2) == a1
但我想第一个更有可读性。这三个是普通的ruby(不是rails)。