2012-05-23 24 views
11

làm người đầu tiên câu hỏi Dự án Euler: cách tổng hợp các bội số của 3 và 5 từ 1 đến 1000, tôi đã đưa ra với điều này (khá đơn giản)ruby ​​tiêm với điều kiện trong khối?

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

nhưng tôi nghĩ rằng điều này sẽ làm việc nhưng không, có thể ai đó cho tôi thấy những gì tôi đang làm sai, hoặc tại sao nó không hoạt động?

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

cảm ơn!

Trả lời

22

inject chuyển kết quả của khối qua lần lặp tiếp theo làm đối số đầu tiên. Khối của bạn sẽ trả lại nil khi tuyên bố if của bạn là sai, sau đó được trả lại là sum.

Để có được câu trả lời đúng, khối nên trả lại số tiền hiện tại khi đó là sai:

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 } 

cũng sẽ làm việc (chú ý +=).

+0

cảm ơn câu trả lời thay thế. Điều này gần hơn với thiết lập ban đầu của tôi và vì vậy tôi có thể làm theo cách này (dễ đọc hơn đối với tôi), tôi chấp nhận câu trả lời đầu tiên vì lời giải thích về lỗi - 'aha!' thời điểm với tôi đã giúp – Tonys

3

Câu trả lời bổ sung: nếu bạn chuẩn bị giải quyết các vấn đề Euler, bạn nên bắt đầu xây dựng các phần mở rộng của riêng bạn về mã có thể sử dụng lại. Trong trường hợp này, phần mở rộng đầu tiên sẽ là Enumerable#sum:

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

Và bây giờ bạn có thể viết một giải pháp ngăn cách tình trạng của summatory (bạn có thể đọc nó out loud và nó có ý nghĩa, đó là điển hình của chức năng/declarative phong cách):

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

bạn thậm chí có thể đẩy nó trở thành một bước xa hơn và tạo Fixnum#divisible_by? vì vậy bạn có thể viết:

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

thêm: ở đây nó không phải là một vấn đề, nhưng sau này về việc triển khai nghiêm ngặt (những người sử dụng mảng) sẽ đòi hỏi quá nhiều bộ nhớ. Hãy thử sau đó với laziness:

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

Đây là thông tin tuyệt vời. Tôi sẽ theo dõi nó như một vài câu hỏi và tôi thấy sự hữu ích của lời khuyên. Cảm ơn! – Tonys

2

Hoặc sử dụng & proc tự giải quyết.

(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(:+) để hoàn thành.

Các vấn đề liên quan