2010-10-15 18 views
121

Jaki jest najlepszy, najbardziej elegancki/skuteczny sposób na sprawdzenie, czy tablica zawiera dowolny element z drugiej macierzy?Tablica zawiera jakąkolwiek wartość z innej tablicy?

Dwa przykłady poniżej, próbując odpowiedzieć na pytanie, czy 'żywność' zawiera żadnego elementu z 'sery':

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 

Odpowiedz

211
(cheeses & foods).empty? 

on robi to samo, co pisał Injekt, ale to już skompilowany działania w języku.

Jak Marc-André Lafortune powiedział w komentarzach, & działa w czasie liniowym podczas any? + include? będzie kwadratowa. W przypadku większych zestawów danych czas liniowy będzie szybszy. W przypadku małych zestawów danych, any? + include? może być szybsze, jak pokazuje odpowiedź Lee Jarvisa.

+12

Ruby wykonuje przecięcie, budując skrót, więc zdecydowanie nie jest to to samo co 'any? {... include?}', Które będzie cyklicznie przechodzić przez każdą potencjalną parę elementów. Przecięcie '& 'jest zatem czasem liniowym, podczas gdy' any? 'Będzie kwadratowe. Byłoby równoważne, gdyby "sery" były "Set" zamiast "Array". –

+1

Podczas sprawdzania, czy tablica zawiera element z innej tablicy, czy nie miałoby większego sensu (serów i potraw). ponieważ zwraca prawdziwą wartość, jeśli tablice "faktycznie zawierają którekolwiek z tych samych elementów? –

+0

@RyanFrancis, docs: 'any?': * Metoda zwraca wartość true, jeśli blok nigdy zwraca wartość inną niż false lub zero. * 'Empty?': * Zwraca wartość true, jeśli self nie zawiera żadnych elementów. * – Nakilon

18

Jak o 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 scenariusz:

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 

Wynik:

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

ta powinna być prawidłowa odpowiedź. Nawet myśl, że ten drugi jest bardziej czytelny. To znacznie szybsze rozwiązanie. –

+0

Możesz to poprawić, zamieniając 'sery' w zestaw. – akuhn

+1

Prowadził mój własny benchmark tutaj na ruby ​​2.2.7 i 2.3.4 i "any ?, include?" Był najszybszy, zestaw rozłączny najwolniejszy: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865932cd01a8b497 – Jared

19

Możesz sprawdzić, czy przecięcie jest puste.

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

To nie wygląda na prawidłową składnię 2.0 - 'Set.new (CHEESES) .disjoint? Set.new (FOODS) 'może? – Jared

+0

Również w moim (nienaukowym) benchmarku, zestaw rozłączny był znacznie wolniejszy niż inne metody: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared

+1

Dzięki za komentarze. Nie jestem pewien, dlaczego to nie był Set.new, ale właśnie go zredagowałem. Próbowałem testów wydajności w wersji 2.4.1. Mój zrobił lepiej, ale nadal nie najlepiej, używając rozłącznych zestawów zawierających więcej słów. Wprowadziłem moją wersję w komentarzu do twojego sedna. Też myślę, że 'rozłączny?' Jest bardzo elegancki, szczególnie w porównaniu do "jakiegokolwiek ?, co?". Pierwotne pytanie zadawało zarówno eleganckie, jak i skuteczne. – davidkovsky

Powiązane problemy