2012-05-23 11 views
11

robi pierwszy projekt Euler pytanie: zsumowanie wielokrotności 3 i 5 w zakresie od 1 do 1000, wpadłem na ten (bardzo prosty)Ruby wstrzyknąć warunkowe w bloku?

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

ale myślałem, że to będzie działać, ale tak nie jest, można ktoś pokazuje mi, co robię źle, albo dlaczego to nie działa?

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

dziękuję!

Odpowiedz

22

inject przekazuje wynik bloku do następnej iteracji jako pierwszy argument. Twój blok zwróci nil, gdy twoja instrukcja if będzie fałszywa, a następnie zostanie przekazana jako sum.

Aby uzyskać właściwą odpowiedź, blok powinien zwrócić aktualną sumę, gdy jest fałszywa:

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 } 

Czy też działa (uwaga +=).

+0

dzięki za odpowiedź alt. Jest to bliższe mojej początkowej konfiguracji, więc prawdopodobnie zrobiłbym to w ten sposób (bardziej czytelne dla mnie), przyjąłem pierwszą odpowiedź z powodu wyjaśnienia błędu - "aha!" chwila mi pomogła – Tonys

3

Uzupełniająca odpowiedź: jeśli masz zamiar zająć się problemami Eulera, powinieneś zacząć budować własne rozszerzenia kodu wielokrotnego użytku. W tym przypadku, pierwsze rozszerzenie byłoby Enumerable#sum:

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

I teraz można napisać rozwiązanie, które oddziela stan summatory (można go przeczytać na głos i to ma sens, że to typowe dla funkcjonalnego/deklaratywnej style):

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

można nawet przesunąć o jeden krok dalej i stworzyć Fixnum#divisible_by? więc można napisać:

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

Więcej: tutaj jest nie stanowi problemu, ale później ścisłe implementacje (używające tablic) będą wymagały zbyt dużo pamięci. Spróbuj następnie laziness:

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

To jest świetna informacja. Zamierzam podążać za tym jako kilka pytań i widzę użyteczność porady. Dzięki! – Tonys

2

Lub użyj & proc która rozwiązuje siebie.

(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(:+) za kompletność.