While Loops in Ruby and Converting to a Function - ruby

I'm on Chapter 33 of Learn Ruby the Hard Way.
Extra credit exercise 1 asks:
Convert this while loop to a function that you can call, and replace 6
in the test (i < 6) with a variable.
The code:
i = 0
numbers = []
while i < 6
puts "At the top i is #{i}"
numbers.push(i)
i = i + 1
puts "Numbers now: #{numbers}"
puts "At the bottom i is #{i}"
end
puts "The numbers: "
for num in numbers
puts num
end
My attempt:
i = 0
numbers = []
def loops
while i < 6
puts "At the top i is #{i}"
numbers.push(i)
i = i + 1
puts "Numbers now: #{numbers}"
puts "At the bottom i is #{i}"
end
end
loops
puts "The numbers: "
for num in numbers
puts num
end
As you can see, I got as far as trying to make the block into a function, not yet making the 6 a variable.
Error:
ex33.rb:5:in `loops': undefined local variable or method `i' for main:Object (Na
meError)
from ex33.rb:15:in `<main>'
from ex33.rb:15:in `<main>'
What am I doing wrong?
EDIT: Okay, improved it a little. Now the numbers variable is out of scope...
def loops (i, second_number)
numbers = []
while i < second_number
puts "At the top i is #{i}"
i = i + 1
numbers.push(i)
puts "Numbers now: #{numbers}"
puts "At the bottom i is #{i}"
end
end
loops(0,6)
puts "The numbers: "
for num in numbers
puts num
end

As #steenslag says, i is out of scope within loops. I would not recommend switching to using #i because i is only used by loops.
Your function is a utility that can be used to produce an array of numbers. The function uses i to figure out how far through it is (but the caller of the function doesn't care about this, it only wants the resulting numbers). The function also needs to return numbers, so move that inside loops too.
def loops
i = 0
numbers = []
while i < 6
puts "At the top i is #{i}"
numbers.push(i)
i = i + 1
puts "Numbers now: #{numbers}"
puts "At the bottom i is #{i}"
end
end
You now have to think about the fact that the caller of loops can no longer see numbers. Good luck with your learning.

When you say def, i goes out of scope. The method can't "see" it. Use #i in stead (the # gives the variable a greater "visibility"), or move the i=6 inside the method, or figure out how to use parameters with a method.

I may have misread the 'convert the while loop' but my solution was:
def loop(x, y)
i = 0
numbers = []
while i < y
puts "At the top i is #{i}"
numbers.push(i)
i += 1
puts "Numbers now: ", numbers
puts "At the bottom i is #{i}"
end
puts "The numbers: "
# remember you can write this 2 other ways?
numbers.each {|num| puts num }
end
loop(1, 6)

Related

Measuring the time to sort each item using bubblesort

I wanted to add a timer which would count the time of sorting the five highest numbers with detailing each one individually, that is, the timer starts counting when sorting starts, then saves the time of sorting the first highest number, then resets and counts the time of the second highest number until the first five numbers are counted.
Here is my code, I don't know how to place timer so it will count what I want
def bubble_sort(tablica)
n = tablica.length
liczba_max = tablica.max(5){ |a, b| a<=>b}
loop do
zamienione = false
(n-1).times do |i|
if tablica[i] > tablica[i+1]
tablica[i], tablica[i+1] = tablica[i+1], tablica[i]
zamienione = true
end
end
break if not zamienione
end
puts "Sorted array:"
tablica
end
puts "size of array:"
ilosc_liczb = gets.chomp()
i = 0
liczba = Array.new(ilosc_liczb.to_i)
puts "Unsorted array:"
while i < ilosc_liczb.to_i
nubmers = Random.new_seed
liczba[i] = nubmers
puts liczba[i]
i += 1
end
puts bubble_sort(liczba)
puts "5th number"
puts liczba[-5]
Please help me

How do you pass a range of values as arguments to a method?

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

comparison of Fixnum with nil failed (ArgumentError)

i'm starting in ruby and i don't know why this is happening.
this is my code.
def buble_sort(a)
i = 0
print a.size()
while i < a.size() do
if a[i] > a[i+1] then
temp = a[i]
a[i] = temp
a[i+1] = a[i]
end
i = i + 1
end
return a
end
puts "Amount of elements in your array"
n = gets.chomp.to_i
a = []
n.times do |num|
puts "input your element #{num}"
a <<gets.chomp.to_i
end
puts a
a = buble_sort(a)
puts "Array sorted #{a}"
And the output give me this error:
4burbuja.rb:6:in >': comparison of Fixnum with nil failed (ArgumentError)
from burbuja.rb:6:inbuble_sort'
from burbuja.rb:24:in `'
I understand that you are learning ruby and want to implement your own bubble sort. a.sort is easy but doesn't teach you anything. I'm glad you are learning by doing! There is a flaw in your bubble sort method. You are incrementing i and using it as an index for your array on each iteration. It could take many iterations to complete, in the worst case it will take n**2 (n squared) iterations which will clearly be more than the elements in your array. However if your code worked as I expect you expected it to run it would only make one pass on the array.
This is a classic ruby bubble sort. (with your having the user fill the array from console)
Notice that we continue to process the ENTIRE array multiple times until we no longer need to swap any values.
def bubble_sort(array)
n = array.length
puts "Sorting your array of #{n} items"
loop do #will loop forever till we break
#When we go through the entire array
#and don't have to swap then the array
#is sorted
swapped = false
(n-1).times do |i|
print "*" #just to illustrate how many iterations occur
if array[i] > array[i+1]
array[i], array[i+1] = array[i+1], array[i] #swap these values, no pesky temp variable
swapped = true
end
end
break if not swapped #we are done exit the loop
end
array #return the sorted array
end
puts "Amount of elements in your array"
n = gets.chomp.to_i
a = []
n.times do |num|
puts "input your element #{num}"
a <<gets.chomp.to_i
end
puts a
a = bubble_sort(a)
puts "Array sorted #{a}"
Here is an example of it being run via console
Cyclops% ruby sort_test.rb
Amount of elements in your array
6
input your element 0
5465463
input your element 1
3421
input your element 2
432143
input your element 3
234123
input your element 4
645
input your element 5
1
5465463
3421
432143
234123
645
1
Sorting your array of 6 items
******************************
Array sorted [1, 645, 3421, 234123, 432143, 5465463]
Cyclops%

How do I total the random numbers generated in ruby

I have the code, that will generate random numbers, unless the generated random number is 0. When the result is 0, the loop breaks.
So when the loop breaks, I want a code, that keeps adding the random numbers that kept generated and display it at the last. Can I do that in ruby?
def batting
loop do
runs = [0,1,2,3,4,5,6]
myruns = runs.shuffle.first
Newscore =
puts "Press W to hit a shot"
user_input = gets.chomp
while user_input.include? "W"
puts myruns
until myruns == 0
break
Score = Score + myruns
break
This is throwing Dynamic Constant assignment error at Score = Score + myruns which I basically think, its wrong, since the myruns keep changing at every generated event?
So, I would want to create a new variable, that would store the total of all the random numbers generated until the generated random number is 0.
Could anyone help?
May be you are looking for something like this ?
def batting
runs = [0,1,2,3,4,5,6]
final_score = 0
puts "Press W to hit a shot"
user_input = gets.chomp
while user_input.include? "W"
myruns = runs.sample
if myruns != 0
final_score += myruns
else
break
end
puts "myruns=#{myruns}","final_score=#{final_score}"
puts "Press W to hit a shot"
user_input = gets.chomp
end
puts "myruns=#{myruns}","final_score=#{final_score}"
end
You can do something like this:
def batting
loop.with_object([]) do |_,obj|
x = rand 7
x == 0 ? raise(StopIteration) : obj << x
end.sum
end
batting #=> 33
batting #=> 0
batting #=> 18
Using loop this continually creates random numbers from 0 - 6 with rand 7. We use a ternary operator to stop the loop with StopIteration if x == 0, otherwise we push x into the obj array (which is initially []). Finally we sum the obj array.
Key methods: loop, Enumerable#with_object, rand, Array#sum

Comma assignment (why right go first?) i.e. n,m = 1, 2?

In the process of figuring out blocks and yields I came across these comma-separated assignments:
def fibit
n,m =1,1
loop do |variable|
yield n
n,m = m,n+m # this line
puts "n is #{n} m is #{m}"
end
end
fibit do |num|
puts "Next : #{num}"
break if num > 100
end
Why does the m get assigned first in this scenario?
Does the last one always go first? If so why?
This was also seen as only e has the value of 1 meaning e went first?
e,r=1
puts r
puts "-------"
puts e
Also, does anyone have an idea why the code-block versions just executes, where if I write the same code with no code block I actually need to call the method for it to run?
def fibit
n,m =1,1
loop do |variable|
puts "Next : #{n}"
break if n > 100
n,m = m,n+m
end
end
fibit
If I didn't have the last line it wouldn't run. Where in the first one I don't actually call the fibit method? Or is the block kicking it off?
m does not get assigned first. When using multiple assignments, all right hand side calculations are done before any assignment to the left hand side.
That's how this code works:
a = 1
b = 3
a, b = b, a
a
# => 3
b
# => 1
This would not be possible if the assignment was done serially, since you would get that both would be either equal 1 or 3.
To further prove my point, simply swap the assignment of n and m in your code, and you'll find that the result is the same:
def fibit
n,m =1,1
loop do |variable|
yield n
m,n = n+m,m # this line
puts "n is #{n} m is #{m}"
end
end
fibit do |num|
puts "Next : #{num}"
break if num > 100
end

Resources