2012-05-23 19 views
11

fare la prima domanda Project Euler: sommando i multipli di 3 e 5 tra 1 e 1000, sono arrivato fino a questo (piuttosto semplice)rubino iniettare con condizionale nel blocco?

sum = 0 
1.upto(999) { |i| sum += i if 0 == i%3 || 0 == i%5 } 
sum 

ma ho pensato che questo avrebbe funzionato ma non è così, posso qualcuno mi mostra cosa sto facendo male, o perché non funziona?

1.upto(999).inject(0) { |sum, i| sum + i if 0 == i%3 || 0 == i%5 } 

grazie!

risposta

22

inject passa il risultato del blocco alla successiva iterazione come primo argomento. Il blocco restituirà nil quando l'istruzione if è falsa, che viene quindi restituita come sum.

per ottenere la risposta corretta, il blocco deve restituire la somma corrente quando è falsa:

1.upto(999).inject(0) { |sum, i| (0 == i%3 || 0 == i%5) ? sum + i : sum } 
2
1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 == i%5; sum } 

potrebbe anche funzionare (notare il +=).

+0

grazie per la risposta alt. Questo è più vicino al mio setup iniziale e quindi probabilmente lo farei in questo modo (più leggibile per me), ho accettato la prima risposta a causa della spiegazione dell'errore - il 'aha!' momento per me aiutato – Tonys

3

Risposta complementare: se stai per affrontare i problemi di Eulero dovresti iniziare a creare le tue estensioni di codice riutilizzabile. In questo caso, la prima estensione sarebbe Enumerable#sum:

module Enumerable 
    def sum 
    inject(0, :+) 
    end 
end 

E ora è possibile scrivere una soluzione che separa la condizione della sommatoria (si può leggere ad alta voce e ha senso, che è tipico di funzionali/dichiarativa style):

1.upto(999).select { |x| x % 3 == 0 || x % 5 == 0 }.sum 

si potrebbe anche spingere un ulteriore passo avanti e creare Fixnum#divisible_by? modo da poter scrivere:

1.upto(999).select { |x| x.divisible_by?(3) || x.divisible_by?(5) }.sum 

più: qui è non è un problema, ma in seguito implementazioni rigorose (quelle che usano gli array) richiederanno troppa memoria. Prova poi con laziness:

require 'lazy' 
1.upto(999).lazy.select { |x| x % 3 == 0 || x % 5 == 0 }.sum 
+0

Questa è una grande informazione. Ho intenzione di seguirlo come alcune domande e vedo l'utilità del consiglio. Grazie! – Tonys

2

In alternativa, utilizzare & proc che affronta sé.

(1..999).select{|x| x%3==0||x%5==0}.inject &:+ 
1

(1..999).to_a.keep_if{|d| d%3 == 0 || d%5 == 0}.reduce(:+) per completezza.

Problemi correlati