开发者

Syntax Error in Ruby, Unexpected Pipe Character in a Do

开发者 https://www.devze.com 2023-01-06 20:23 出处:网络
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

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
0

精彩评论

暂无评论...
验证码 换一张
取 消