2010-10-15 4 views
121

Какой лучший, самый элегантный/эффективный способ проверить, содержит ли массив какой-либо элемент из второго массива?Array включает любое значение из другого массива?

Два примера ниже, пытаясь ответить на вопрос, означает 'пища' содержит какой-либо элемент из 'сыров':

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? будет квадратичным. Для больших наборов данных линейное время будет быстрее. Для небольших наборов данных any? + include? может быть быстрее, как показано ответом Ли Джарвиса.

+12

Ruby делает пересечение, создавая хэш, поэтому он определенно не совпадает с «any? {... include?}», Который будет циклически проходить через каждую потенциальную пару элементов. Таким образом, пересечение '&' представляет собой линейное время, а 'any?' Будет квадратичным. Это было бы эквивалентно, если бы «сыры» были «Set» вместо «Array». –

+1

При проверке, содержит ли массив элемент из другого массива, не имеет смысла делать (сыры и продукты) .any? как это возвращает истинное значение, если массивы действительно содержат какие-либо из этих элементов? –

+0

@RyanFrancis, docs: 'any?': * Метод возвращает true, если блок когда-либо возвращает значение, отличное от false или nil. * 'Empty?': * Возвращает true, если self не содержит элементов. * – Nakilon

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 

Benchmark сценарий:

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

это должно быть правильным ответом. Даже подумал, что другой читаем. Это гораздо более быстрое решение. –

+0

Вы можете улучшить это, превратив «сыры» в набор. – akuhn

+1

Ran мой собственный бенчмарк здесь на ruby ​​2.2.7 и 2.3.4 и 'any ?, include?' Был самым быстрым, set disjoint самым медленным: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared

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

+0

Также в моем (ненаучном) контролере установка disjoint была значительно медленнее, чем другие методы: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared

+1

Спасибо за ваши комментарии. Я не уверен, почему это не было Set.new, но я только что отредактировал его. Я пробовал ваши тесты производительности в 2.4.1. Моя работала лучше, но все же не всегда использовала несвязанные множества, содержащие больше слов. Я поставил свою версию в комментарии к вашему тексту. Я также думаю, что «disjoint?» Очень элегантный, особенно по сравнению с «any ?, include?». Первоначальный вопрос задал вопрос об элегантности и эффективности. – davidkovsky

Смежные вопросы