2015-09-30 10 views
5

corrispondenza Ho il seguente array:Rubino enumerabile - trovare fino a n occorrenze di elemento

arr = [1, 3, 2, 5, 2, 4, 2, 2, 4, 4, 2, 2, 4, 2, 1, 5] 

Voglio una matrice contenente i primi tre elementi dispari.

So che potrei fare questo:

arr.select(&:odd?).take(3) 

ma voglio evitare scorrendo l'intero array, e invece tornare ancora una volta ho trovato la terza partita.

mi si avvicinò con la seguente soluzione, che a mio avviso fa quello che voglio:

my_arr.each_with_object([]) do |el, memo| 
    memo << el if el.odd?; break memo if memo.size == 3 
end 

ma c'è un modo più semplice/idiomatica di fare questo?

risposta

9

Utilizzare un lazy enumerator con Enumerable#lazy:

arr.lazy.select(&:odd?).take(3).force 
# => [1, 3, 5] 

force viene utilizzato per forzare l'enumeratore pigro per valutare. Oppure, si potrebbe usare first come è ansioso:

arr.lazy.select(&:odd?).first(3) 
# => [1, 3, 5] 
+0

Ho confermato che 'force' funziona, ma non riesco a trovare la documentazione tranne quella in [ruby lang] (http://docs.ruby-lang.org/ja/2.1.0/method/Enumerator=3a= 3aLazy/i/force.html). Sai perché non è nella documentazione di RDoc? È perché è solo un alias di 'to_a'? – sawa

+3

FYI - Potresti usare 'arr.lazy.select (&: odd?). First (3)' ed evitare il 'force' -' take' è pigro mentre 'first' no. – Myst

+0

@sawa Non riesco a trovarlo neanche io. Se lo trovi, sentiti libero di modificare la mia risposta. –

5

codice e l'esempio

arr.take_while.with_object([]) do |e,a| 
    a << e if e.odd? 
    a.size < 3 
end 
    #=> [1, 3, 5] 

Benchmark

require 'fruity' 

def compare_em(arr, m) 
    compare(
    lazy:  -> { arr.lazy.select(&:odd?).take(m).force }, 
    take_while: -> { arr.take_while.with_object([]) { |e,a| 
         a << e if e.odd?; a.size < m } } 
) 
end 

n = 1e6 
arr = (1..n).to_a.shuffle 

ottenere i primi 1.000 elementi dispari:

compare_em(arr, 1e3) 
    # Running each test 8 times. Test will take about 1 second. 
    # take_while is faster than lazy by 2x ± 1.0 

ottenere i primi 10.000 elementi dispari:

compare_em(arr, 1e4) 
    # Running each test once. Test will take about 1 second. 
    # take_while is faster than lazy by 2x ± 1.0 

ottenere gli elementi dispari primo 100.000:

compare_em(arr, 1e5) 
    # Running each test once. Test will take about 3 seconds. 
    # take_while is faster than lazy by 2x ± 0.1 

Sono sorpreso lazy fatto abbastanza bene, come spesso è molto più lento, relativamente, nei parametri di riferimento.

Problemi correlati