I'll try to be concise this time around! I'm still working Project Euler, this time back to #2. My real issue here is I'm terrible with Ruby. When I run the following code
x开发者_开发知识库 = 1
y = 2
sum = 2
while x >= 4_000_000 do |x|
sum += y if y % 2 == 0
z = x + y
x = x ^ y # xor magic
y = x ^ y # xor magic
x = x ^ y # xor magic
y = z
end
p sum
My interpreter kicks out the following output:
/Users/Andy/Documents/Programming/Ruby/ProjectEuler/P2.rb:4: syntax error, unexpected '|'
while x >= 4_000_000 do |x|
^
I'm reading why's (Poignant) Guide to Ruby, and I'm pretty sure I have the pipe syntax correct for the Do. Could someone point out what I'm doing wrong here? I've tried messing around in a lot of different ways and am coming up short handed
while (x >= 4_000_000)
foo
end
You don't even have to pass in x
, because it's accessible in the scope of the enclosing block.
while
does not take a block. Remove the do |x|
part.
while
is not a method that takes a block, it is a ruby looping statement. It considers the part between the while
and do
(or newline) to be the logical test and the part between the do (or newline) and end
keyword to be the loop body.
while x < 10 do x += 1; puts x; end
while x < 10
x += 1
puts x
end
Contrast this with something like the Array's each
method which takes in a block. Here the each method calls your block for each element of the array (passed into the block as x)
[1,2,3].each do |x|
puts x
end
You accidentally combined the two, asking the while loop to call your code block with the loop counter to be passed in as x. That is not how while works... hence the parsing exception.
What an interesting question! It inspired me to take a shot at the problem, too. Here's my solution.
First, some preparatory work:
class Enumerator
def lazy_select
Enumerator.new do |y|
each do |el|
y.yield(el) if yield el
end
end
end
alias_method :lazy_find_all, :lazy_select
end
module Enumerable
def sum
reduce(:+)
end
end
module Math
ROOT5 = Math.sqrt(5)
PHI = 0.5 + ROOT5/2
def self.fibonacci(n)
Integer(0.5 + PHI**n/ROOT5)
end
end
class Integer
def fibonacci
Math.fibonacci(self)
end
end
Now an Enumerator
which generates an infinite sequence of Fibonacci Numbers:
fibs = Enumerator.new do |y|
n = -1
loop do
y.yield (n += 1).fibonacci
end
end
And the nice thing is that we can now directly express the original problem statement in code:
Find the sum of all the even-valued terms in the sequence which do not exceed four million.
puts fibs.lazy_find_all(&:even?).take_while {|n| n <= 4_000_000 }.sum
I think that this is a much more Rubyish way to solve the problem. You write in your question that you are terrible with Ruby. But that's not actually the problem. The real problem is that you are good with C! In other words, the real problem is that you simply aren't writing Ruby, you are writing C with Ruby syntax.
Two good examples are:
y % 2 == 0
and
x = x ^ y
y = x ^ y
x = x ^ y
The Ruby way to write these would be
y.even?
and
x, y = y, x
精彩评论