2010-10-15 9 views
121

Qual è il modo migliore, più elegante/efficiente per verificare se un array contiene elementi di un secondo array?La matrice include qualsiasi valore da un altro array?

Due esempi di seguito, nel tentativo di rispondere alla domanda fa 'alimenti' contengono alcun elemento da 'formaggi':

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 

risposta

211
(cheeses & foods).empty? 

Si fa lo stesso, quello che ha postato Injekt, ma è già compilato azioni in una lingua.

Come ha detto Marc-André Lafortune nei commenti, & lavori in tempo lineare, mentre any? + include? saranno quadratica. Per set di dati più grandi, il tempo lineare sarà più veloce. Per i set di dati di piccole dimensioni, any? + include? potrebbe essere più veloce, come mostrato dalla risposta di Lee Jarvis.

+12

Ruby fa l'intersezione costruendo un hash, quindi non è assolutamente lo stesso di "any? {... include?}" Che scorre in ciclo ogni potenziale coppia di elementi. L'intersezione '&' è quindi un tempo lineare mentre il 'any?' Sarà quadratico. Sarebbe equivalente se 'formaggi' fosse un' Set' invece di un 'Array'. –

+1

Quando si controlla se un array contiene un elemento di un altro array, non avrebbe più senso fare (formaggi e alimenti) .any? come questo restituisce un valore vero se gli array 'contengono effettivamente uno degli stessi elementi? –

+0

@RyanFrancis, docs: 'any?': * Il metodo restituisce true se il blocco restituisce mai un valore diverso da false o nil. * 'Vuoto?': * Restituisce true se self non contiene elementi. * – Nakilon

18

Come su 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 

sceneggiatura 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 

Risultato:

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

Questa dovrebbe essere la risposta corretta. Anche se l'altro è più leggibile. Questa è una soluzione molto più veloce –

+0

Puoi migliorare questo trasformando i "formaggi" in un set. – akuhn

+1

Esegui il mio benchmark qui su ruby ​​2.2.7 e 2.3.4 e "any ?, include?" È stato il più veloce, impostare disgiunto il più lento: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared

19

È possibile verificare se l'intersezione è vuota.

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

Non sembra una sintassi 2.0 valida - 'Set.new (CHEESES) .disjoint? Set.new (FOODS) 'forse? – Jared

+0

Anche nel mio benchmark (non scientifico), impostare disgiunto era significativamente più lento rispetto ad altri metodi: https://gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497 – Jared

+1

Grazie per i vostri commenti. Non sono sicuro del motivo per cui non era Set.new ma l'ho appena modificato. Ho provato i tuoi benchmark delle prestazioni in 2.4.1. Il mio ha fatto meglio, ma non è ancora il caso di utilizzare set disgiunti contenenti più parole. Ho messo la mia versione in un commento sul tuo succo. Penso anche che "disgiunto?" Sia molto elegante, soprattutto se paragonato a "any ?, include?". La domanda originale ha fatto domande sia eleganti che efficienti. – davidkovsky

Problemi correlati