how to save variable within a while loop - ruby

I have a variable x which is set to 10. And I want to write a while loop that increments that. I know you can easily just use a for-loop for this, but easy isn't fun. The code I have is:
def add(a)
g = a + 1
puts g
end
def loop(d)
x = 0
while x <= 4
x += 1
add(d)
end
end
loop(9)
When ran I get 9, four times. How can I get this code to have an output of 9, 10, 11, 12?

Your problem is that you say add(d) and d is the parameter of your loop, loop(d). Ruby does blindly what you tell him : loop(9), so here d=9 and remains equal to 9. You need to increment the value of d. To do that add will now return the incremented value, and we assign the returned value to d (in loop).
To solve your problem you will want to do something like :
def add(a)
g = a + 1
puts g
g
end
def loop(d)
x = 0
while x <= 4
x += 1
d = add(d)
end
end
loop(9)
BUT and that's a huge but, your code is not the ruby way at all.
If I were to do it I would do it like this:
def loop(start_number, repeat_number, increment)
repeat_number.times do
start_number += increment
p start_number
end
end
loop(9, 4, 1)

If you rly wanna to use while and your expected outpit is Array numbers 9 up to 12.
Simply define the array variable before while loop and return it like this:
def loop(number)
x, a = 0, []
while x <= 3
a << number + x
x += 1
end
a
end
loop(9)
# => [9, 10, 11, 12]
BETTER WAY
But better way is use some ruby functions like times and map
in this case we use times and map
def loop(d)
4.times.map{|i| d + i}
end
p loop(9)
# => [9, 10, 11, 12]
maybe this will helps.

Related

Lua -randomly select 3 numbers (out of 250) in every run/event, but excluding one

I would like to get random 3 numbers (e.g. 3, 177, 244) from an array of 0 to 250 in every event, and excluding a pre-defined number between 0 and 250 (e.g 220).
For example,
In the 1st event (push button),
I got 220 from another data set, so I need random numbers like a=3, b=177, c=244 (a, b, c should not be 220).
In the 2nd event (push button),
I got 15 from another data set,, so I need random numbers like a=77, b=109, c=166 (a, b, c should not be 15)
Do you have any good idea to implement this?
Looking for a good mathematician! Cheers.
Based on #Evan Wrynn, I tried the following, but I need one more step to get random 3 numbers in a table, right. Basically I try to put all numbers in t. d is a variable I got from another source. The outcome should be t which contains 3 random numbers (i.e. t={4, 88, 221} (except 85 in this case)). Currently t seems to get duplicate numbers :(. Completely alternative idea is also welcome.
d = 85
dt = {}
t = {}
table.insert(dt,d)
while table.getn(t) < 3 do
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
else
return table.insert(t,x)
end
end
end
GetMathRandomExclude(1,250,dt)
end
for i, v in ipairs(t) do
print(i, v)
end
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
return x
end
d = 62
dt = {}
t = {}
table.insert(dt,d)
while table.getn(t) < 3 do
local randomnum = GetMathRandomExclude(1,250,dt)
table.insert(t,randomnum)
table.insert(dt,randomnum)
end
for i, v in ipairs(t) do
print(i, v)
end
The first problem you had was the random function, it would check only the first number as you returned after the if statement. This is sorted by putting it at the end of the function.
you can remove table.insert(dt,randomnum) if you don't want the numbers picked not to be added to the exclusion
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
if x == exclude then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
return x
end
print(GetMathRandomExclude(1,3,2)) -> (when called 10 times I got "3" 7 times and "1" 3 times.
If the number = the number to exclude it than recalls the function.
You can check with a table to make it have multiple exclusions.
EDIT:
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
if type(exclude) == "table" then
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
else
if x == exclude then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
return x
end
print(GetMathRandomExclude(1,100,{85,62})) -> 40
GetMathRandomExclude(NUMBER lowerbound, NUMBER upperbound, NUMBER OR TABLE exclude)
in answers above we roll random number, and if it should be excluded, we roll another random number until we get one that should not be excluded. Drawback is if size of "ok" set and "exclude" set are comparable, we may reroll often.
i propose another approach, which i'll describe in example: we want random from 1 to 10 excluding 5. So we roll random from 1 to 9, and if our result is >4 then we add 1 to result. So we get random from 1 to 10 excluding 5. It can be implemented in following way:
local function get_random_n(min, max , exclude, n)
local result = {}
for i = 1, n do
table.sort(exclude)
result[i] = math.random(min, max - #exclude)
for j = 1, #exclude do
if result[i] > (exclude[j]-1) then
result[i]=result[i]+1
end
end
exclude[#exclude+1]=result[i]
end
return result
end
local function test()
for j = 1, 10 do
local x = get_random_n(1, 10, {3,5,7}, 7)
print("========")
for k = 1, #x do
print(x[k])
end
end
end

I don't understand this method

I'm a beginner in Ruby and I don't understand what this code is doing, could you explain it to me, please?
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
def defines a method. Methods can be used to run the same code on different values. For example, lets say you wanted to get the square of a number:
def square(n)
n * n
end
Now I can do that with different values and I don't have to repeat n * n:
square(1) # => 1
square(2) # => 4
square(3) # => 9
= is an assignment.
s = 0 basically says, behind the name s, there is now a zero.
0..n-1 - constructs a range that holds all numbers between 0 and n - 1. For example:
puts (0..3).to_a
# 0
# 1
# 2
# 3
for assigns i each consecutive value of the range. It loops through all values. So first i is 0, then 1, then ... n - 1.
s += i is a shorthand for s = s + i. In other words, increments the existing value of s by i on each iteration.
The s at the end just says that the method (remember the thing we opened with def) will give you back the value of s. In other words - the sum we accumulated so far.
There is your programming lesson in 5 minutes.
This example isn't idiomatic Ruby code even if it is syntactically valid. Ruby hardly ever uses the for construct, iterators are more flexible. This might seem strange if you come from another language background where for is the backbone of many programs.
In any case, the program breaks down to this:
# Define a method called a which takes an argument n
def a(n)
# Assign 0 to the local variable s
s = 0
# For each value i in the range 0 through n minus one...
for i in 0..n-1
# ...add that value to s.
s += i
end
# The result of this method is s, the sum of those values.
s
end
The more Ruby way of expressing this is to use times:
def a(n)
s = 0
# Repeat this block n times, and in each iteration i will represent
# a value in the range 0 to n-1 in order.
n.times do |i|
s += i
end
s
end
That's just addressing the for issue. Already the code is more readable, mind you, where it's n.times do something. The do ... end block represents a chunk of code that's used for each iteration. Ruby blocks might be a little bewildering at first but understanding them is absolutely essential to being effective in Ruby.
Taking this one step further:
def a(n)
# For each element i in the range 0 to n-1...
(0..n-1).reduce |sum, i|
# ...add i to the sum and use that as the sum in the next round.
sum + i
end
end
The reduce method is one of the simple tools in Ruby that's quite potent if used effectively. It allows you to quickly spin through lists of things and compact them down to a single value, hence the name. It's also known as inject which is just an alias for the same thing.
You can also use short-hand for this:
def a(n)
# For each element in the range 0 to n-1, combine them with +
# and return that as the result of this method.
(0..n-1).reduce(&:+)
end
Where here &:+ is shorthand for { |a,b| a + b }, just as &:x would be short for { |a,b| a.x(b) }.
As you are a beginner in Ruby, let's start from the small slices.
0..n-1 => [0, n-1]. E.g. 0..3 => 0, 1, 2, 3 => [0, 3]
for i in 0.. n-1 => this is a for loop. i traverses [0, n-1].
s += i is same as s = s + i
So. Method a(n) initializes s = 0 then in the for loop i traverse [0, n - 1] and s = s + i
At the end of this method there is an s. Ruby omits key words return. so you can see it as return s
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
is same as
def a(n)
s = 0
for i in 0..n-1
s = s + i
end
return s
end
a(4) = 0 + 1 + 2 + 3 = 6
Hope this is helpful.
The method a(n) calculates the sums of the first n natural numbers.
Example:
when n=4, then s = 0+1+2+3 = 6
Let's go symbol by symbol!
def a(n)
This is the start of a function definition, and you're defining the function a that takes a single parameter, n - all typical software stuff. Notably, you can define a function on other things, too:
foo = "foo"
def foo.bar
"bar"
end
foo.bar() # "bar"
"foo".bar # NoMethodError
Next line:
s = 0
In this line, you're both declaring the variable s, and setting it's initial value to 0. Also typical programming stuff.
Notably, the value of the entire expression; s = 0, is the value of s after the assignment:
s = 0
r = t = s += 1 # You can think: r = (t = (s += 1) )
# r and t are now 1
Next line:
for i in 0..n-1
This is starting a loop; specifically a for ... in ... loop. This one a little harder to unpack, but the entire statement is basically: "for each integer between 0 and n-1, assign that number to i and then do something". In fact, in Ruby, another way to write this line is:
(0..n-1).each do |i|
This line and your line are exactly the same.
For single line loops, you can use { and } instead of do and end:
(0..n-1).each{|i| s += i }
This line and your for loop are exactly the same.
(0..n-1) is a range. Ranges are super fun! You can use a lot of things to make up a range, particularly, time:
(Time.now..Time.new(2017, 1, 1)) # Now, until Jan 1st in 2017
You can also change the "step size", so that instead of every integer, it's, say, every 1/10:
(0..5).step(0.1).to_a # [0.0, 0.1, 0.2, ...]
Also, you can make the range exclude the last value:
(0..5).to_a # [0, 1, 2, 3, 4, 5]
(0...5).to_a # [0, 1, 2, 3, 4]
Next line!
s += i
Usually read aloud a "plus-equals". It's literally the same as: s = s + 1. AFAIK, almost every operator in Ruby can be paired up this way:
s = 5
s -= 2 # 3
s *= 4 # 12
s /= 2 # 6
s %= 4 # 2
# etc
Final lines (we'll take these as a group):
end
s
end
The "blocks" (groups of code) that are started by def and for need to be ended, that's what you're doing here.
But also!
Everything in Ruby has a value. Every expression has a value (including assignment, as you saw with line 2), and every block of code. The default value of a block is the value of the last expression in that block.
For your function, the last expression is simply s, and so the value of the expression is the value of s, after all is said and done. This is literally the same as:
return s
end
For the loop, it's weirder - it ends up being the evaluated range.
This example may make it clearer:
n = 5
s = 0
x = for i in (0..n-1)
s += i
end
# x is (0..4)
To recap, another way to write you function is:
def a(n)
s = 0
(0..n-1).each{ |i| s = s + i }
return s
end
Questions?

Sum of Fibonacci even number

I'm currently working on small ruby projects from project Euler site. I was given a task to sum even fibonacci numbers that are less than 4 millions. Unfortunately there is a small bug in my code, because when I change the limit e.i. to 100, it prints 188 instead of 44. Surprisingly this program gives the right answer but i don't really know in what way my code is wrong.
a=[]; a[0]=1; a[1]=1;
i = 1
while a[-1] < 608
a[i+1]=(a[i] + a[i-1])
i +=1
end
x = 0
a.each do |num|
if num % 2 == 0
x += num
end
end
print "The sum of even Fibonacci number is: #{x}"
The problem comes from the second iteration. You are stopping the generation of Fibonacci numbers when one of the numbers cross the limit (ie when the last number is > 100).
It turns out that after the generation step, the array is [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], this explains your wrong result 188 = 144+44.
So, your code works only when the last element generated is odd, which is the case in Euler's problem test. In order to correct that, change your second iteration from a.each do ... end to a[0...-1].each do ... end In order to iterate through the array except the last element.
BTW I would recommend you not to use an array here.
You are just wasting memory and ruby is losing time on extending it (this can be solved via Array.new(ARRAY_SIZE)).
Since you don't actually need a fibbonaci sequence you can just have something like this:
LIMIT = 4_000_000
a = 1
b = 1
next_number = a + b
sum = 0
while next_number < LIMIT
sum += next_number if next_number.even?
a = b
b = next_number
next_number = a + b # or next_number += a
end
UPD. Oh my god I don't know why this question appeared in my feed. Sorry for necroposting:)

implement shell sort by ruby

I try to implement shell sort by ruby.
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
end
end
puts list.inspect
break if d == 1
end
list
end
puts shell_sort([10,9,8,7,6,5,4,3,2,1]).inspect
but the result is incorrect.
=>[2, 1, 3, 4, 5, 7, 6, 8, 9, 10]
I don't know where going wrong, hope someone can help me. Thanks in advance!
I referenced Shell Sort in here : Shell Sort - Wikepedia, and from that I have understood your algorithm is wrong. Iteration of gap sequence is alright, I mean you iterate only upto d/2 == 1.
But for a gap, let's say 2, you simply iterate from 0 to list.length-2 and swap every j and j+2 elements if list[j] is greater than list[j+2]. That isn't even a proper insertion sort, and Shell Sort requires Insertion sorts on gaps. Also Shell Sort requires that after you do an x gap sort, every xth element, starting from anywhere will be sorted (see the example run on the link and you can verify yourself).
A case where it can wrong in a 2 gap sort pass :
list = 5,4,3,2,1
j = 0 passed :
list = 3,4,5,2,1
j = 1 passed :
list = 3,2,5,4,1
j = 2 passed
list = 3,2,1,4,5
After it completes, you can see that every 2nd element starting from 0 isn't in a sorted order. I suggest that you learn Insertion Sort first, then understand where and how it is used in Shell Sort, and try again, if you want to do it by yourself.
Anyway, I have written one (save it for later if you want) taking your method as a base, with a lot of comments. Hope you get the idea through this. Also tried to make the outputs clarify the how the algorithm works.
def shell_sort(list)
d = list.length
return -1 if d == 0
# You select and iterate over your gap sequence here.
until d/2 == 0 do
d = d / 2
# Now you pick up an index i, and make sure every dth element,
# starting from i is sorted.
# i = 0
# while i < list.length do
0.step(list.length) do |i|
# Okay we picked up index i. Now it's just plain insertion sort.
# Only difference is that we take elements with constant gap,
# rather than taking them up serially.
# igap = i + d
# while igap < list.length do
(i+d).step(list.length-1, d) do |igap|
# Just like insertion sort, we take up the last most value.
# So that we can shift values greater than list[igap] to its side,
# and assign it to a proper position we find for it later.
temp = list[igap]
j = igap
while j >= i do
break if list[j] >= list[j - d]
list[j] = list[j-d]
j -= d
end
# Okay this is where it belongs.
list[j] = temp
#igap += d
end
# i += 1
end
puts "#{d} sort done, the list now : "
puts list.inspect
end
list
end
list = [10,9,8,7,6,5,4,3,2,1]
puts "List before sort : "
puts list.inspect
shell_sort(list)
puts "Sorted list : "
puts list.inspect
I think your algorithm needs a little tweaking.
The reason it fails is simply because on the last run (when d == 1) the smallest element (1) isn't near enough the first element to swap it in in one go.
The easiest way to make it work is to "restart" your inner loop whenever elements switch places. So, a little bit rough solution would be something like
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
d *= 2
break
end
end
This solution is of course far from optimal, but should achieve required results with as little code as possible.
You should just do a last run on array. To simplify your code I extracted exchange part into standalone fucntion so you could see now where you should do this:
def exchange e, list
(0...(list.length-e)).each do |j|
if list[j] >= list[j+e]
list[j], list[j+e] = list[j+e], list[j]
end
end
end
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
exchange(d, list)
puts list.inspect
if d == 1
exchange(d, list)
break
end
end
list
end
arr = [10,9,8,7,6,5,4,3,2,1]
p shell_sort(arr)
Result:
#> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Hashes vs Lambdas

I found two examples that looked close to each other for finding Fibonacci numbers:
Lambda
fibonacci = ->(x){ x < 2 ? x : fibonacci[x-1] + fibonacci[x-2] }
fibonacci[6] # => 8
Hash
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
fibonacci[6] # => 8
I used both hashes and lambdas in ruby before, but not like this. This is more of a way of storing a function:
if x < 2
x
else
fibonacci[x-1] + fibonacci[x-2]
Can you explain in detail how this is working? Is this using recursion?
What are the differences between hashes like this and lambdas?
Yes it is using recursion. If we look at the code in the {}-brackets we can figure out the answer. Let's start looking at the hash. The values after new keyword is the default value. A value that will be assigned if the value does not already exist in the hash.
hash = Hash.new
p hash['new_value'] #=> nil
default_value_hash = Hash.new(0)
puts default_value_hash['new_value'] #=> 0
hash_with_block = Hash.new{|h,x| x}
puts hash_with_block['new_value'] #=> 'new_value'
So when we declare
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
we are basically saying - Create a new hash with a default value. If we ask for a number (x) smaller or equal to two, just return the input (x). Else, give us the sum of the dictionary values where the key is x-1 and x-2. Basically the Fibonacci algorithm. If x-1 and x-2 does not exist, it runs the same code again until the two basic input values are 1 and 2.
The difference between the two approaches is that the hash saves the values (in a hash...). This can be a huge advantage in some cases. Every time the lambda is called it needs to recalculate the values for all numbers below the called value.
# Let's create a counter to keep track of the number of time the lambda is called.
# Please do not use global variables in real code. I am just lazy here.
#lambda_counter = 0
fibonacci_lambda = ->(x){
#lambda_counter += 1
x < 2 ? x : fibonacci_lambda[x-1] + fibonacci_lambda[x-2]
}
p (1..20).map{|x| fibonacci_lambda[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p #lambda_counter # => 57290
# lambda called 57290 times!
#hash_counter = 0
fibonacci_hash = Hash.new{ |h,x|
#hash_counter += 1
h[x] = x < 2 ? x : h[x-1] + h[x-2]
}
p (1..20).map{|x| fibonacci_hash[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p #hash_counter # => 21
# Only called 21 times!
The reason for the big difference in calls is the nature of recursion. The lambda does not store its values and when the value for 10 is calculated it recalculates the value for 3 more than 20 times. In the hash this value can be stored and saved for later.
In the first case, you are defining a recursion which will be called recursively.
In the case of the hash, the values will also be computed recursively, but stored and then access for giving the result.
Lambda
fibonacci = ->(x){ x < 2 ? x : fibonacci[x-1] + fibonacci[x-2] }
fibonacci[6]
fibonacci # => <Proc:0x2d026a0#(irb):5 (lambda)>
Hash
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
fibonacci[6]
fibonacci # => {1=>1, 0=>0, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8}
In one case, you are not leaving any footprint in memory, whereas the hash will continue to keep the computed value. So it depends on what you need.
If you need to access fibonacci[6] one more time, the lambda will recompute the result, whereas the hash will give you the result immediately without redo the calculations.
What are the differences between hashes like this and lambdas?
lambdas and hashes have nothing in common. Your question is like asking:
What are the differences between methods and arrays?
It's just that Hashes can specify a default value for a non-existent key:
h = Hash.new(10)
h["a"] = 2
puts h["a"]
puts h["b"]
--output:--
2
10
Hashes also provide a way to dynamically specify the default value: you can provide a block. Here is an example:
h = Hash.new do |h, key|
h[key] = key.length
end
puts h['hello']
puts h['hi']
p h
--output:--
5
2
{"hello"=>5, "hi"=>2}
When you access a non-existent key, the block is called, and the block can do whatever you want. So someone cleverly figured out that you could create a hash and specify a default value that calculated fibonacci numbers. Here is how it works:
h = Hash.new do |h, key|
if key < 2
h[key] = key
else
h[key] = h[key-1] + h[key-2]
end
end
That creates the Hash h, which is a Hash with no keys or values. If you then write:
puts h[3]
...3 is a non-existent key, so the block is called with the args h and 3. The else clause in the block executes, which gives you:
h[3-1] + h[3-2]
or:
h[2] + h[1]
But to evaluate that statement, ruby has to first evaluate h[2]. But when ruby looks up h[2] in the hash, the key 2 is a non-existent key, so the block is called with the args h and 2, giving you:
(h[2-1] + h[2-2]) + h[1]
or:
(h[1] + h[0]) + h[1]
To evaluate that statement, ruby first has to evaluate the first h[1], and when ruby tries to look up h[1] in the hash, 1 is a non existent key, so the block is called with the args h and 1. This time the if branch executes, causing this to happen:
h[1] = 1
and 1 is returned as the value of h[1], giving you this:
(1 + h[0]) + h[1]
Then ruby looks up h[0], and because 0 is a non-existent key, the block is called with the args h and 0, and the if clause executes and does this:
h[0] = 0
and 0 is returned as the value of h[0], giving you this:
(1 + 0) + h[1]
Then ruby looks up h[1] in the hash, and this time the key 1 exists, and it has a value of 1, giving you:
(1 + 0) + 1
And that is equal to 2, so h[3] is set equal to 2. After calling h[3], you get this output:
puts h[3]
p h
--output:--
2
{1=>1, 0=>0, 2=>1, 3=>2}
As you can see, the previous calculations are all cached in the hash, which means that those calculations don't have to be performed again for other fibonacci numbers.

Resources