Using ruby 1.9.3, I need to do the following:
test_ids.each do |x|
if x == 1
y = x+1
elsif x == 2
y = x+2
elsif x == 3
(end loop here, start over with next test_id)
else
y = x+4
end
end
I just need the loop to continue with the next object in the array if a condition is met instead of continuing throughout the script. How is this possible?
EDIT:
The end goal is something like this:
case x
when 1
abort
when 2
...
else
...
end
puts x+2
So as you can see, x is being used after the if case statement. I need to not run the puts statement if x = 1. I don't want to abort the script and terminate it altogether, I just want to skip that array object and go to the next one. Any suggestions?
= assigns a value to x so your code only executes x = 1 inside the loop.
Instead you need a comparison using == in your if statements.
You could have avoided this using a case statement:
case x
when 1
...
when 2
...
when 3
...
else
...
end
In my experience using case tends to clarify code compared to multiple if/else/elsif.
You are looking for the next command.
test_ids.each do |x|
if x == 1
y = x+1
elsif x == 2
y = x+2
elsif x == 3
next
else
y = x+4
end
end
Related
I am calling a method I created and trying to pass a range of values as the arguments.
My code:
def prime_numbers (x)
i = 1
count = 0
until i > x
if x % i == 0
count += 1
end
i += 1
end
if count > 2
puts "count is: " + count.to_s
p x.to_s + " is not prime."
p false
elsif count == 2
puts "count is: " + count.to_s
p x.to_s + " is prime."
p true
end
end
prime_numbers (5)
puts
prime_numbers (25)
puts
prime_numbers (31)
puts
prime_numbers (1..100) #This is the one I care about that is throwing an error
Desired output:
count is: 2
"5 is prime."
true
count is: 3
"25 is not prime."
false
count is: 2
"31 is prime."
true
This would be desired for all the numbers within the range.
What I think I've done incorrectly or may still need to do:
I could use an array and somehow incorporate blocks to do all of this.
I'm missing something very simple in my syntax
Syntax in my parameter list needs to be changed
Thank you in advance for your time answering this.
Your method is named prime_numbers, but that is not exactly what it does. It is hard to come up with a good name: it does too much. That said, you could call it for every number in a range like this :
(1..100).each{|n| prime_numbers(n) }
In order to pass an array, you should define a method in a way that it can process an array.
In your code from what I can see is you are getting a parameter x and then applying an operator > to that which in case of a range will throw an error.
When (1..100) is passed as an argument x becomes an array what you might wanna do is something like this
def prime_numbers (x)
y = x.class == Range ? x : [x] # to make sure you have an array
y.each do |number|
...... you code here
end
end
PS you would want to replace number in the above example. Or you could rename your parameter x
This question already has answers here:
Shortcut to make case/switch return a value
(4 answers)
Closed 6 years ago.
I have this code
(1..50).each do |num|
case num
when num % 4 == 0, num % 6 == 0
puts 'Cluck'
when num % 4 == 0
puts 'Cluck Cluck'
when num % 5 == 0
puts 'Cluck Cluck Cluck'
else
puts num
end
end
For some odd reason, instead of putting cluck cluck on the fourth line or cluck on the 24th line, it's just putting a list of 1 through 100. I can't figure out what's wrong with the switch statement. The first when using the comma or && doesn't change anything either (which I don't believe it should).
Problems
case a when b
case a
when b
tests if a is equal to b.
In your case, a is a number (num) and b is a boolean (num % 4 == 0) so this never happens.
when b,c
Another problem is that
case
when b,c
tests if b or c.
If you want to check that num is divisible by 24, you need b and c.
Solution
Remove num from case and use logical and (&&) :
(1..100).each do |num|
case
when num % 4 == 0 && num % 6 == 0
## or just :
# when num % 24 == 0
puts 'Cluck'
when num % 4 == 0
puts 'Cluck Cluck'
when num % 5 == 0
puts 'Cluck Cluck Cluck'
else
puts num
end
end
Oh well, Eric's answer is right on the money. I'd just add this as a reference -
It doesn’t end there though you can use a case statement without giving it a value to match against, which allows a case statement to mimic the behavior of an if statement, e.g.:
print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
puts 'String has letters'
else
puts 'String has no numbers or letters'
end
I read over this guide quick, and it seems to be that you're trying to use the case as an if statement, but you supplied a value to match against.
Because you gave num as the first argument of case, it's expecting to match against it. The problem is, your conditions evaluate to boolean values, and num is a number, so they'll never match, and the else condition will always be run.
Remove the num from the start of the case.
I need to write a loop
for x in (1..y)
where the y variable can be changed somehow. How can I do that?
For example:
for x in (1..y/x)
But it does not work.
Normally we'd use a loop do with a guard clause:
x = 1
loop do
break if x >= y
x += 1
...
end
Make sure y is larger than x or it'll never do anything. y can change if necessary and as long as it's greater than x the loop will continue. As soon as y drops below x the loop will terminate on the next iteration.
Note: I use >= because testing for equality is a bug-in-waiting. Sometimes we try to compare where x starts out greater than y or we are incrementing a float and comparing it to an integer or another float and using == and never hit the magic "equal" causing the loop to run away. Instead always check for a greater-than-or-equal to end the loop.
I think you might be confused about return values. This actually works fine, it's just that the return value is equal to the original range.
y = 4
for x in (1..y)
puts x
end
# 1
# 2
# 3
# 4
#=> 1..4
Here's a code snippet to prove it.
Basically I'm looping through a matrix of arrays adding up the columns, but it stops right before the 2nd iteration of the 9.times loop. If I change y = 1 it will perform the action and stop at y = 2 and so on.
def new_feature(board)
x=0
y=0
vertical = []
while y < 9
9.times do
vertical << board[x][y]
x += 1
end
puts vertical.reduce(:+)
vertical = []
y += 1
end
end
You never reset x back to 0, so in the second while iteration your x starts with 9 where it finished last time, not 0. This makes board[9], which is presumably out of bounds and thus nil; and then nil[1] crashes your code.
Note that you can write 9.times do |x| ... end to have x count from 0 to 8 without any manual counting, since times passes the current iteration number into the block.
Also, a more Rubyish way to sum columns:
board.transpose.map { |row| row.reduce(&:+) }
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