Ruby While Loop Print - ruby

I'm trying to get the numbers in numbers to print out.
But when the if-expression comes before the numbers are appended, it doesn't seem to print. Only if I put the if-expression after, it will. Why is this?
numbers = []
while numbers.size < 5
if numbers.size == 5
puts numbers
break
end
numbers << rand(0..99)
end

This happens because you have numbers.size < 5.
As soon as numbers.size is 5, the while is no longer true. You can use <= (or numbers.size < 6) if you want it to ONLY print when it is exactly 5.
numbers = []
while numbers.size <= 5
if numbers.size == 5
puts numbers
break
end
numbers << rand(0..99)
end
Or you could write this in a more ruby style:
numbers = []
5.times do numbers << rand(0..99) end
puts numbers

1.Case 1: If statement placed before appending
The reason is because the loop will not execute when numbers.size == 5 because the condition you've set is while numbers.size < 5.
2. If statement is placed after appending
Placing the if statement after appending the numbers list will work because you're still within the body of the loop i.e. you're still executing the loop for which the condition you set was true.

Your code doesn't work because the while loop exits before the if condition is true.
What's more, the if block is unnecessary and makes your code confusing and inefficient.
Lemme refactor it for ya...
Generates an array of 5 random integers between 0 and 99 and then prints it
numbers = []
while numbers.size < 5
numbers << rand(0..99)
end
puts numbers

Related

Why is this switch statement not working? [duplicate]

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.

Syntax error? Ruby bug? Issue with instance variable incrementing with += 1?

def isPrime?(num)
i = 2
#isFalse = 0
while i < num
divisible = ((num % i) == 0)
if divisible
#isFalse += 1
return false
end
i += 1
end
true
end
def primes(max)
startTime = Time.now
(2..max).each do |p|
puts "#{p} #{isPrime?(p)}"
end
endTime = Time.now
puts "--------------------------------------------------"
puts " FALSE values in range from (2 thru #{max}): #{#isFalse} \n TRUE values in range from (2 thru #{max}): #{max-1-#isFalse}"
puts "\nTotal time to calculate is #{endTime - startTime} seconds!"
end
primes(10)
isPrime? checks if a given number is a prime number.
primes loads a range of numbers and checks if each is a prime.
I want to know how many numbers are prime within the range and how many aren't.
I added #isFalse += 1 thinking I can increment each time false is returned so that I can determine how many numbers in the range are false and use this to subtract from max to get how many numbers are true.
Entire code is working correctly except #isFalse is not properly incrementing. Why is that? Thanks for the help.
--UPDATE--
My Output: added puts "About to increment #isFalse" before #isFalse += 1
2 true
3 true
About to increment #isFalse
4 false
5 true
About to increment #isFalse
6 false
7 true
About to increment #isFalse
8 false
About to increment #isFalse
9 false
About to increment #isFalse
10 false
--------------------------------------------------
FALSE values in range from (2 thru 10): 1
TRUE values in range from (2 thru 10): 8
Each time isPrime? is called, #isFalse is reset to 0. So the result of #isFalse being 1 is from the last time isPrime? was called (with num equal to 10, incrementing #isFalse to 1).
It seems that you are trying to find out the number of primes in that range using #isFalse. If that is the case, you should instead use the following modification of your code (although, I do not recommend checking for primes in this way, and the code is really inefficient):
Basically, I removed the instance variable #isFalse altogether, and checked whether a number is prime or not in your second method, instead. The code is much cleaner that way, and really does what you intend it to do.
The problem with your code is that #isFalse is being reset to 0 everytime your first method isPrime? was being called, and hence, does not properly reflect the number of primes in the given range.
def isPrime?(num)
i = 2
while i < num
divisible = ((num % i) == 0)
return false if divisible
i += 1
end
true
end
def primes(max)
startTime = Time.now
is_prime = 0
(2..max).each do |p|
if isPrime?(p)
is_prime += 1
puts p
end
endTime = Time.now
puts "--------------------------------------------------"
puts " FALSE values in range from (2 thru #{max}): #{is_prime} \n TRUE values in range from (2 thru #{max}): #{max-1-is_prime}"
puts "\nTotal time to calculate is #{endTime - startTime} seconds!"
end
primes(10)
As your question has been answered, I would like to suggest a more Ruby-like solution:
You want the method is_prime? to do nothing other than determine if num is prime:
def is_prime?(num)
(2...num).each {|i| return false if num % i == 0}
true
end
Do your counting of primes in the method nbr_primes.
def nbr_primes(max)
return false if max < 2
(2..max).reduce(0) {|tot, i| tot + (is_prime?(i) ? 1 : 0)}
end
p nbr_primes(20) # => 8
A few points:
I removed the references to time and the output formatting as they are not central to the question.
It's a Ruby convention to name methods with lower case letters and underscores.
(2...num), because it has three dots, is the sequence from 2 to (and including) num - 1. We could instead write (2..num-1) (two dots), which is favored by some.
(2..max).reduce(0) {|tot, i|...} iterates over i from 2 to and including max. tot, which is reduce's accumulator, is incremented by 1 for each number between 2 and max that is found to be prime. The expression returns the value of tot, which in turn is returned by the method nbr_primes. inject is a synonym for reduce.
In checking whether a number n is prime, you only have to check if its divisible by numbers up to Math.sqrt(n).to_i.
With require 'prime', you don't have to reinvent the wheel. For example, Prime.prime?(7) #=> true, and Prime.take_while {|p| p <= 10}.size #=> [2, 3, 5, 7].size + 1 # => 4.
#isFalse = 0 is inside your isPrime? method. Get it out of there!

Random number generator issues in Ruby

My intention here is just to fill up an array with numbers in order from 1, to a random number between 1 and 1000. However, after repeatedly running this code (about 50 times), the highest number I have gotten is 120, and only twice has it been over 100. The majority of my arrays were anywhere between 0 and 60. This behavior appears off to me. Am I doing something wrong?
my_array = []
i = 0
while i <= rand(1000)
my_array << i
i += 1
end
puts my_array.count
puts my_array
Your function is broken, because you're checking versus the random number. Do this:
(0..1000).collect{ rand(1000) }
This will return an array of one thousand random numbers.
Or, closer to your code:
my_array = []
i = 0
while i <= 1000
my_array << rand(1000)
i += 1
end
As per comment, what you want is:
(1..rand(1000))
(1..rand(1000)).to_a
The first results in a range, which is "easier to carry around", the second results in the populated array.
(Edit) Note:
(1..10) is inclusive - (1..10).to_a == [1,2,3,4,5,6,7,8,9,10]
(1...10) is partially exclusive - (1...10).to_a == [1,2,3,4,5,6,7,8,9] - it does not include the end of the array, but still includes the beginning.
It sounds like you want:
(1...rand(1000)).to_a
Additionally, I have amended my code to reflect what I was trying to accomplish initially. My problem was that every time I looped through my code I generated a new random number. Because of this, as 'i' incremented toward 1000 it became more and more likely that a random number would be generated that was lower than 'i'. My fix, while not as elegant as the solution above that I accepted, was to store the random number in a variable, BEFORE attempting to use it in a loop. Thanks again. Here is the amended code:
my_array = []
i = 0
g = rand(1000)
while i <= g
my_array << i
i += 1
end
puts my_array.count
puts my_array

Confusion with the order of execution when `next` with `unless` in ruby

The next statement is used to skip a part of the loop and continue with the next iteration of the loop. It can be used in combination with for and while statements.
I have seen people using next if there is complicated piece of code after some condition is being evaluated i.e
next if #state!=:some_state
# some long complicated code
Now here I have played with the next in my IRB as below :
n = 1
loop do
n = n + 1
next unless n == 10
print "Good"
break
end
# Good=> nil
The above one understood. Nicely clear.
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi" unless n == 5
p "good"
break
end
#1hi
#2hi
#3hi
#4"good"
#=> nil
In the above code, couldn't understand about which order the lines puts "hi" and unless n == 5 executed. Which executed first?
The below one leads to the infinite Loop.
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi"; 2 + 3 unless n == 5
p "good"
break
end
whereas this one is good:
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi", 2 + 3 unless n == 5
p "good"
break
end
#1hi
#5
#2hi
#5
#3hi
#5
#4"good"
#=> nil
Please help me here to understand - how does this one resolve that forever loop ?
A semicolon is evaled as a line break so:
next puts "hi"; 2 + 3 unless n == 5
would be equivalent to:
next puts "hi"
2 + 3 unless n == 5
Therefore, next will always be called and you'll have an infinite loop.
The comma is evaled as passing a set of arguments (which is interpreted as an array by puts method signature), so:
next puts "hi", 2 + 3 unless n == 5
is equivalent to:
next puts("hi", 2 + 3) unless n == 5
Regarding the execution order of puts and unless - consider the following:
unless n == 5
next puts "hi"
end
In this example, it is obvious that unless is evaluated first, then if the condition passed is evaluated to false the next puts "hi" statement is executed. Well:
next puts "hi" unless n == 5
is shorthand for exactly the same thing. So the unless modifier will always be evaluated first. Naturally, if you insert a semicolon in the middle, it would cause this to be evaluated differently, since the semicolon is evaluated as a line break.
The conditional has to execute first, otherwise, how would it even know whether to evaluate any expressions involving the statement?
As to your second question, the value of the next expression is ignored for loops, the value in the expression is only useful to return a value from a block. So, the only thing that makes your loop end is the break.

How to execute multiple succeeding functions in 1 line in Ruby?

I have two succeeding function with the same condition and I wonder what is the best way to write this? I know the one way to do this is using if (condition) ... end, but I'm wondering if I can do it in one-line similar to bash, '[$n == $value] echo "$n" && break'.
n = 0
loop do
puts n if n == value # puts and break is having the same condition, but
break if n == value # can we do it in one line?
n += 1
end
Because n is truthy, you can use the 'and' joiner. It reads really nicely:
n = 0
loop do
puts n and break if n == value
n += 1
end
--edit--
As pointed out in comments, that won't actually work because puts returns nil, which isn't truthy. My bad. You can use 'or' instead, but that doesn't read nicely. So I'd say just group the statements with parenthesis.
n = 0
loop do
(puts n; break) if n == value
n += 1
end
You could also change the puts method to return the value it prints, and that would work with 'and', but that's probably not the smartest idea :)
I'm guessing your actual code is different to what you've pasted, so if the first method in your chain returns something, you can use 'and'.
One easy way is to just parenthesize the statements:
ruby-1.9.1-p378 > 0.upto(5) do |n|
ruby-1.9.1-p378 > (puts n; break;) if n == 3
ruby-1.9.1-p378 ?> puts ">>#{n}<<"
ruby-1.9.1-p378 ?> end
>>0<<
>>1<<
>>2<<
3
If it's a bit much to put in parentheses, a begin-end will do the trick:
0.upto(5) do |n|
begin
puts "I found a matching n!"
puts n
puts "And if you multiply it by 10, it is #{10*n}"
break;
end if n == 3
puts "((#{n}))"
end
Output:
((0))
((1))
((2))
I found a matching n!
3
And if you multiply it by 10, it is 30
proc { puts n; break; }.() if n == 3
One of the golden rules of Ruby is that if you are writing a loop, you are probably doing it wrong. In this particular case, all that your loop is doing is to find an element in a collection. In Ruby, there already is a method for finding an element in a collection: Enumerable#find. There is no need to write your own.
So, the code gets simplified to:
puts (0...1.0/0).find {|n| n == value }
Now that we have a nice declarative formulation of the problem, it is easy to see that (assuming sane equality semantics and sane semantics of value.to_s), this is exactly the same as:
puts value
So, the whole loop was completely unnecessary to begin with.

Resources