2010-10-15 89 views
121

什麼是最好,最優雅/有效的方式來測試一個數組是否包含第二個數組中的元素?下面數組包含來自另一個數組的任何值?

兩個例子,試圖回答的問題是 '食物' 包含的任何元素,從 '奶酪':

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

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

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

回答

211
(cheeses & foods).empty? 

它做同樣的,有什麼公佈injekt,但它已經編譯的語言行動。

至於馬克 - 安德烈·Lafortune在評論中說,&作品線性時間,而any? + include?將二次。對於更大的數據集,線性時間會更快。對於小數據集,如Lee Jarvis的答案所示,any? + include?可能會更快。

+12

Ruby通過構建一個散列來完成交集,所以它絕對不會與'any?{... include?}'不一樣,它將遍歷每一個潛在的元素對。交點'&'因此是線性時間,而'any?'將是二次的。如果「奶酪」是一個「集合」而不是「陣列」,這將是等價的。 – 2010-10-15 15:21:00

+1

當檢查一個數組是否包含另一個數組中的元素時,做它(奶酪和食物)是否更有意義?因爲如果數組實際上包含任何相同的元素,它會返回一個真值。 – 2014-07-15 21:46:31

+0

@RyanFrancis,docs:'any?':*如果塊返回的值不是false或nil,則該方法返回true *:* empty *:如果self不包含任何元素,則返回true * – Nakilon 2014-07-15 22:40:12

18

如何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) 
+0

這應該是正確的答案。甚至認爲另一個更具可讀性。這是一個更快的解決方案 – 2016-10-25 15:24:46

+0

您可以通過將「奶酪」變成一套來改善這一點。 – akuhn 2016-12-26 01:00:35

+1

在ruby 2.2.7和2.3.4以及'any ?,包括?'上跑我自己的基準,這是最快的,設置不相交最慢:https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared 2017-05-03 17:25:54

19

您可以檢查交叉點是否爲空。

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

這看起來不像有效的2.0語法 - 「Set.new(CHEESES).disjoint? Set.new(FOODS)'也許? – Jared 2017-05-03 17:18:11

+0

同樣在我的(不科學的)基準測試中,設置不相交顯着比其他方法慢:https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared 2017-05-03 17:24:43

+1

感謝您的意見。我不確定爲什麼它不是Set.new,但我只是編輯它。我在2.4.1中試過了你的性能基準。我做得更好,但仍然不是最好使用含有更多單詞的不連貫的集合。我把我的版本放在對你的要點的評論中。我也認爲'脫節?'非常優雅,特別是與「任何?」相比,包括?「。原來的問題確實問到優雅和高效。 – davidkovsky 2017-05-04 18:24:57

相關問題