数组包含来自另一个数组的任何值?

Posted

技术标签:

【中文标题】数组包含来自另一个数组的任何值?【英文标题】:Array include any value from another array? 【发布时间】:2011-04-25 21:52:07 【问题描述】:

测试一个数组是否包含第二个数组中的任何元素的最有效方法是什么?

下面两个例子,试图回答问题foods 是否包含来自cheeses 的任何元素:

cheeses = %w(chedder stilton brie mozzarella feta haloumi reblochon)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)

puts cheeses.collect|c| foods.include?(c).include?(true)

puts (cheeses - foods).size < cheeses.size

【问题讨论】:

【参考方案1】:
require "benchmark"
N = 1_000_000
puts "ruby version: #RUBY_VERSION"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?")  N.times  (FOODS & CHEESES).empty?    
  b.report("any?, include?")  N.times  FOODS.any? |food| CHEESES.include?(food)     
  b.report("disjoint?")  N.times  FOODS.to_set.disjoint? CHEESES.to_set 
end  
                      user     system      total        real
&, empty?         0.751068   0.000571   0.751639 (  0.752745)
any?, include?    0.408251   0.000133   0.408384 (  0.408438)
disjoint?        11.616006   0.014806  11.630812 ( 11.637300)

【讨论】:

【参考方案2】:
(cheeses & foods).empty?

正如 Marc-André Lafortune 在 cmets 中所说,&amp; 在线性时间中起作用,而any? + include? 将是二次的。对于较大的数据集,线性时间会更快。对于小型数据集,any? + include? 可能会更快,如 Lee Jarvis 的回答所示——可能是因为&amp; 分配了一个新数组,而另一个解决方案没有分配一个新的数组,而是作为一个简单的嵌套循环返回一个布尔值。

【讨论】:

当检查一个数组是否包含另一个数组的元素时,做 (cheeses & foods).any 不是更有意义吗?因为如果数组确实包含任何相同的元素,这将返回一个真值? @RyanFrancis, docs: any?: 如果块曾返回 false 或 nil 以外的值,则该方法返回 true。 empty?: 返回 true如果 self 不包含任何元素。 @Nakilon 我也很困惑为什么答案不是(cheeses &amp; foods).any? 不是 OP 的问题:奶酪中是否有任何食物?在他的例子中,“feta”在两者中,所以结果应该是正确的,对吧?那么为什么要在路口查看.empty? @SuckerForMayhem,因为 OP 的问题是“如果有 ...?”,而不仅仅是“如果有?”。如果省略“are ...”,则假定为“If any is True?”,并且对于像 [false, false, false] 这样的数组将返回 False,而显然不是空的。 在activerecord级别有实现吗?【参考方案3】:
Set.new(cheeses).disjoint? Set.new(foods)

【讨论】:

同样在我的(不科学的)基准测试中,set disjoint 明显比其他方法慢:gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 感谢您的 cmets。我不知道为什么它不是 Set.new 但我只是编辑了它。我在 2.4.1 中尝试了你的性能基准。我的表现更好,但仍然不是最好的使用包含更多单词的脱节集合。我把我的版本放在对你的要点的评论中。我也认为disjoint? 非常优雅,尤其是与“任何?,包括?”相比。最初的问题确实询问了优雅和高效。 .to_set 方法在这里很有用 cheeses.to_set.disjoint?(foods.to_set)【参考方案4】:

Enumerable#any?怎么样

>> cheeses = %w(chedder stilton brie mozzarella feta haloumi)
=> ["chedder", "stilton", "brie", "mozzarella", "feta", "haloumi"]
>> foods = %w(pizza feta foods bread biscuits yoghurt bacon)
=> ["pizza", "feta", "foods", "bread", "biscuits", "yoghurt", "bacon"]
>> foods.any? |food| cheeses.include?(food) 
=> true

基准脚本:

require "benchmark"
N = 1_000_000
puts "ruby version: #RUBY_VERSION"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?")  N.times  (FOODS & CHEESES).empty?  
  b.report("any?, include?")  N.times  FOODS.any? |food| CHEESES.include?(food)   
end

结果:

ruby version: 2.1.9
                      user     system      total        real
&, empty?         1.170000   0.000000   1.170000 (  1.172507)
any?, include?    0.660000   0.000000   0.660000 (  0.666015)

【讨论】:

您可以通过将cheeses 变成一个集合来改进这一点。 在 ruby​​ 2.2.7 和 2.3.4 上运行我自己的基准测试,any?, include? 最快,设置不相交最慢:gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 该基准测试因提到的具体示例而有偏差,不一定适用于更一般的情况。如果两个数组之间没有共同元素怎么办?如果数组在每次传递中的顺序不同怎么办?如果 feta 出现在两个数组的末尾怎么办?正如 Marc-André 所说,集合交集在线性时间内执行,因此对于一般情况而言它更具可扩展性是有道理的,而不是纯粹用于澄清问题的一个特定示例。【参考方案5】:

你可以检查路口是否为空。

cheeses = %w(chedder stilton brie mozzarella feta haloumi)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)
foods & cheeses
=> ["feta"] 
(foods & cheeses).empty?
=> false

【讨论】:

以上是关于数组包含来自另一个数组的任何值?的主要内容,如果未能解决你的问题,请参考以下文章

包含来自另一个文件的数组(nodejs)

如何检查一个数组是不是包含另一个数组的任何元素

检查一个数组是不是包含 JavaScript 中另一个数组的任何元素

检查一个数组是不是包含 JavaScript 中另一个数组的任何元素

Presto 数组包含来自另一列的值(超集 SQL 查询)

使用来自另一个哈希的新值更新了 Ruby 哈希数组