program using while with array values - ruby

I am trying to write a small program that goes through an array's values outputting each individual value. When it reaches 15 it stops and outputs "too big".
Why is my logic below wrong, it makes sense to me..
x = [10,11,12,13,14,15,16,17,18]
def counting
for x[y]
while y < 15
puts y
else
puts "too big"
end
puts counting
I'm just learning sorry if this is a really simple solution.

That's nothing at all like Ruby syntax. You want a .each and a simple if statement:
x.each do |y|
if y < 15
puts y
else
puts "too big"
break
end
end

It appears though you are trying to use Ruby like you would a c-style programming language. It's possible and viable, albeit not recommended.
Code Blocks
Ruby has structure known as code blocks. Code blocks are sort of like anonymous functions.
You can read more about code blocks here.
x = [10,11,12,13,14,15,16,17,18]
# This is a code block.
x.each do |y| # The y between the '|'s is the parameter caught by the code block
if y < 15
puts y
else
puts "Too big."
break # Break out of the loop
end
end

If you want a one liner:
x.each {|y| y < 15 ? puts(y) : puts("too big") || break }
If you insist using while, it can be done as following:
i = 0
while i do
x[i] < 15 ? puts(x[i]) : puts("too big") || break
i+=1
end

I think the cleanest way to do this using while would be:
def counting(x)
i = 0
while x[i] < 15
puts x[i]
i += 1
end
puts 'too big'
end
counting([10,11,12,13,14,15,16,17,18])

Why is my logic below wrong, it makes sense to me..
Given that you program isn't even syntactically legal, it's impossible to tell what its semantics would be if it were syntactically legal, let alone why those semantics were wrong. However, here's an idiomatic Ruby solution (you will almost never use nor see while in any Ruby code, and you will certainly never see for):
puts x.take_while {|n| n < 15 }
puts 'too big'
I prefer writing in point-free style, however in this case the only way to do that is to make use of the symmetry of the condition and invert the order of operands, which will lead to awkward logic:
x.take_while(&15.method(:>))
Ao, in this case I would rather avoid point-free style, because it no longer matches the original specification literally. Instead of "take all numbers less than 15", we now have "take all numbers such that 15 is greater than those numbers", which reads awkward.

Related

Use ruby to go back to early lines and functions

I am making a basic hangman game that will need to keep retracing until the game is over. I'm trying to figure out the correct ruby way to go back to these lines. Here is a rough pseudocode example:
some_function
end
another_function
end
if x > 5 go back to some_function
if x < 5 go back to another_function
Functions are how you run some code somewhere else and return back to where you started. Loops are how you run the same code again and again until some condition is met.
Here is some incomplete code to demonstrate.
def some_function(x)
puts "x is #{x} some function"
end
def another_function(x)
puts "x is #{x} in another function"
end
def something_else(x)
puts "x is #{x} in something else"
end
# I've left are_we_done undefined, it's the condition for
# stopping the loop. I've also left get_x undefined.
while !are_we_done
x = get_x
if x > 5
some_function(x)
elsif x < 5
another_function(x)
else # x is 5
something_else(x)
end
Teaching these fundamentals is beyond a Stack Overflow answer. I would suggest going through a tutorial like Learn Ruby The Hard Way to learn the fundamentals of loops and functions.

How to run a simple Ruby script

I would like to make a program that checks to see if the number you enter is an even number. Sort of like making a leap year program but for any number divisible by 2.
Something along the lines of:
num = gets.chomp
while num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
end
I knows there's something easy that I need to change for it to run.
(btw I just started learning Ruby yesterday!)
There are two problems here.
First being something that others have put, you need to make sure you turn the input into an integer using ".to_i" on your num variable.
Secondly, this code puts you into an infinite loop since you are using a "while" loop.
Since the number is only input once, you get stuck in the "while" loop forever no matter what the input is. Basically, "num" never stops being not 0.
You'd be better off using an if..else statement. Something like:
num = gets.chomp.to_i
if num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
else
puts "that's 0, dude"
end
Integers have two methods for this. They are even? and odd?.
You can use this in your if statement as so:
if num.even?
puts 'yess'
else
puts 'nooo'
end
However, an easier way to write this is with ternary expressions:
puts num.even? ? "yes" : "no"
However, make sure num is an Integer. Anything coming from gets will be a String. So, you should be doing num = gets.chomp.to_i. Anything that is not a number, like "h", will return 0.
"5".to_i #=> 5
"h".to_i #=> 0

Stack too deep error on ruby, sqrt program for learning

So I'm aware of the Math.sqrt(number) method in Ruby, but as part of learning the language I thought it'd be a good idea to make some simple functions. I could be going about finding the square root wrong from a fundamental level, but here's what I did:
def negative?(number)
number < 0
end
#start = 2
def sqrt(number)
if negative? number
puts "Can't do negative"
else
if #start**2 < number
#start += 0.01
sqrt(number)
else
puts "Square root of #{number} is #{#start}!"
end
end
end
def start_sqrt
print "Input text: "
number = Integer(gets.strip)
sqrt(number)
end
begin
start_sqrt
rescue ArgumentError
puts "Need a positive number!"
end
This works fine for smaller numbers, but when I get to entering larger numbers I need to change the value of #start if I want to get an answer, otherwise it says "stack too deep". Is there something wrong I'm doing in the code, or is Ruby doing everything fine and I just am asking it to find the square root of a number in a resource-intensive way? I guess this is maybe even less of a programming question and more of a math question, cause I know I could just do:
def sqrt(number)
if negative? number
puts "Can't do negative"
else
root = number**0.5
puts "Square root of #{number} is #{root}!"
end
end
It looks like Ruby is working as expected. You are asking it to find the square root of a number in a resource-intensive way (recursion).
In fact, you have created a stack overflow error. :)

How to break outer cycle in Ruby?

In Perl, there is an ability to break an outer cycle like this:
AAA: for my $stuff (#otherstuff) {
for my $foo (#bar) {
last AAA if (somethingbad());
}
}
(syntax may be wrong), which uses a loop label to break the outer loop from inside the inner loop. Is there anything similar in Ruby?
Consider throw/catch. Normally the outside loop in the below code will run five times, but with throw you can change it to whatever you like, breaking it in the process. Consider this perfectly valid ruby code:
catch (:done) do
5.times { |i|
5.times { |j|
puts "#{i} #{j}"
throw :done if i + j > 5
}
}
end
What you want is non-local control-flow, which Ruby has several options for doing:
Continuations,
Exceptions, and
throw/catch
Continuations
Pros:
Continuations are the standard mechanism for non-local control-flow. In fact, you can build any non-local control-flow (subroutines, procedures, functions, methods, coroutines, state machines, generators, conditions, exceptions) on top of them: they are pretty much the nicer twin of GOTO.
Cons:
Continuations are not a mandatory part of the Ruby Language Specification, which means that some implementations (XRuby, JRuby, Ruby.NET, IronRuby) don't implement them. So, you can't rely on them.
Exceptions
Pros:
There is a paper that proves mathematically that Exceptions can be more powerful than Continuations. IOW: they can do everything that continuations can do, and more, so you can use them as a replacement for continuations.
Exceptions are universally available.
Cons:
They are called "exceptions" which makes people think that they are "only for exceptional circumstances". This means three things: somebody reading your code might not understand it, the implementation might not be optimized for it (and, yes, exceptions are godawful slow in almost any Ruby implementation) and worst of all, you will get sick of all those people constantly, mindlessly babbling "exceptions are only for exceptional circumstances", as soon as they glance at your code. (Of course, they won't even try to understand what you are doing.)
throw/catch
This is (roughly) what it would look like:
catch :aaa do
stuff.each do |otherstuff|
foo.each do |bar|
throw :aaa if somethingbad
end
end
end
Pros:
The same as exceptions.
In Ruby 1.9, using exceptions for control-flow is actually part of the language specification! Loops, enumerators, iterators and such all use a StopIteration exception for termination.
Cons:
The Ruby community hates them even more than using exceptions for control-flow.
No, there isn't.
Your options are:
put the loop in a method and use return to break from the outer loop
set or return a flag from the inner loop and then check that flag in the outer loop and break from it when the flag is set (which is kind of cumbersome)
use throw/catch to break out of the loop
while c1
while c2
do_break=true
end
next if do_break
end
or "break if do_break" depending on what you want
Perhaps this is what you want? (not tested)
stuff.find do |otherstuff|
foo.find do
somethingbad() && AAA
end
end
The find method keeps looping until the block returns a non null value or the end of the list is hit.
Wrapping an internal method around the loops could do the trick
Example:
test = [1,2,3]
test.each do |num|
def internalHelper
for i in 0..3
for j in 0..3
puts "this should happen only 3 times"
if true
return
end
end
end
end
internalHelper
end
Here you can do a check inside any of the for loops and return from the internal method once a condition is met.
I know I will regret this in the morning but simply using a while loop could do the trick.
x=0
until x==10
x+=1
y=0
until y==10
y+=1
if y==5 && x==3
x,y=10,10
end
end
break if x==10
puts x
end
The if y==5 && x==3 is only an example of an expression turning true.
You may consider adding a flag, which is set inside the inner loop, for controlling the outer loop.
'next' the outer loop
for i in (1 .. 5)
next_outer_loop = false
for j in (1 .. 5)
if j > i
next_outer_loop = true if j % 2 == 0
break
end
puts "i: #{i}, j: #{j}"
end
print "i: #{i} "
if next_outer_loop
puts "with 'next'"
next
end
puts "withOUT 'next'"
end
'break' the outer loop
for i in (1 .. 5)
break_outer_loop = false
for j in (1 .. 5)
if j > i
break_outer_loop = true if i > 3
break
end
puts "i: #{i}, j: #{j}"
end
break if break_outer_loop
puts "i: #{i}"
end

Problem comprehending C-style ruby loops

I find the .each do hard to get to stick, so I was hoping for regular use of C for loop syntax which seems to not work, so I tried a while but still get errors.
I have tried this.
i = 0
while i < SampleCount
samples[i] = amplitude
amplitude *= -1
i++
end
I get complaints about the end statement here.
There are several problems with your code. Rather than just fixing the errors, I'd suggest it's better long-term for you to learn the Ruby way - it will save you time and energy later. In this case, it's
5.times do |i|
samples[i] = amplitude # assumes samples already exists and has 5 entries.
amplitude *= -1
end
If you insist on keeping a similar style, you can do this:
samples = []
i = 0
while i < sample_count
samples << amplitude # add new item to array.
amplitude *= -1
i += 1 # you can't use ++.
end
Note that SampleCount's initial capital letter, by Ruby convention, means a constant, which I'm guessing isn't what you really mean.
I agree with Peter that there are other (more idiomatic) ways to do this in Ruby, but just to be clear: the error message you saw misdirected you. There wasn't anything wrong with your while loop per se. The problem was i++ since there is no ++ operator in Ruby.
This would work just fine:
limit = 10
i = 0
while i < limit
puts i
i += 1
end
Again, I'm not recommending it, but if you're just learning the language, it may help to know where the problem really was.
Ruby has a lot of built-in ways to iterate other than for or while (which tend to be seen less often, as far as I can tell). A few other examples:
(1..10).each do |x| # 1..10 is a range which you can iterate over with each
puts x
end
1.upto(10) { |x| puts x } # Integers have upto and downto methods that can be useful
You originally mentioned trying to use a for loop. Notwithstanding the various other comments in the answers, here's the for loop approach:
for i in 0...5
samples[i] = amplitude
amplitude *= -1
end
Nobody here has actually offered an alternate solution that actually does what Fred originally intended - and that's iterate around the value of the constant SampleCount. So could you do:
SampleCount.times do |i|
Or:
limit = SampleCount
limit.times do |i|
Or:
for i in 0..SampleCount
Would any of those be Ruby-esque enough?
The problem with the end statement is related to i++. Ruby wants to add something. There is no increment operator in Ruby. You need to use i += 1. With that change you can use your C style loop as is.

Resources