while loop within while loop - ruby

"hello" is printed by puts only three times. It is supposed to be printed six times, isn't it?
i = 0
j = 0
while(i != 2)
while(j != 3)
puts "hello"
j += 1
end
i += 1
end

You have to set j to 0 outside the inner while loop.
i = 0
j = 0
while(i != 2)
while(j != 3)
puts "hello"
j += 1
end
# this is needed, as inside the upper loop, you made j to 3 after 3 iteration.
# thus you need to reset it to 0 again, to start again 3 times iteration.
j = 0
i += 1
end
# >> hello
# >> hello
# >> hello
# >> hello
# >> hello
# >> hello
Better is -
i = 0
while(i != 2)
j = 0
while(j != 3)
puts "hello"
j += 1
end
i += 1
end

It may be easier for you if you work with loop {} - even though you have to keep track of the counter yourself, I find it much easier to understand instantly than using while, or x.times which also works fine.

Related

'undefined method `>' for nil:NilClass in ruby

This is my code for converting a user entered string into a Caesar cipher.
puts "text?"
text = gets.chomp
puts "key?"
key = gets.chomp.to_i
plainTex = Array.new
ciphTex = Array.new
j = 0
text.each_byte do |i|
plainTex[j] = i
j += 1
end
j = 0
plainTex.each_entry do |i|
if ( i == 32 )
ciphTex[j] = plainTex[j]
j += 1
end
if( plainTex[j] > 64) and (plainTex[j] < 91 )
if( (plainTex[j] + key) > 91)
ciphTex[j] = (plainTex[j] + key ) - 90
j += 1
else
ciphTex[j] = plainTex[j] + key
j += 1
end
end
if( plainTex[j] > 94) and (plainTex[j] < 123)
if( (plainTex [j] + key) > 122)
ciphTex [j] = (plainTex[j] + key) - 122
j += 1
else
ciphTex[j] = plainTex[j] + key
j += 1
end
end
end
ciphTex.each_entry do |i|
puts i
end
now, I'm getting error :
undefined method `>' for nil:NilClass (NoMethodError)
Search on the web led me to conclude that plainTex might be nil,as the error message is saying( which should not be the case as plainTex is fed data beforehand).
On a side note : the program runs fine when the input string is all lowercase and has no space. I don't know why.
So, what am I doing wrong?
Problem Explained
When you access array with index that is out of bounds you'll get no error, but result nil.
irb --simple-prompt
>> a = [1]
=> [1]
>> a[0]
=> 1
>> a[1]
=> nil
>> a[200]
=> nil
Debugging your code
A little bit of puts statements reveal the issue:
text.each_byte do |i|
plainTex[j] = i
j += 1
end
j = 0
puts "Length: #{plainTex.length}"
plainTex.each_entry do |i|
if ( i == 32 )
ciphTex[j] = plainTex[j]
j += 1
end
puts "j: #{j}"
This is the output
text?
Testing Test
key?
32
Length: 12
j: 0
j: 2
j: 3
j: 4
j: 5
j: 6
j: 7
j: 8
j: 10
j: 11
j: 12
test.rb:30:in `block in <main>': undefined method `>' for nil:NilClass (NoMethodError)
from test.rb:23:in `each'
from test.rb:23:in `each_entry'
from test.rb:23:in `<main>
Last index of array in this case was 11 and you accessed index 12.
You got result nil then you tried to call method > on nil.
Professional debugging
You can install gem pry-byebug and use short aliases s, n for step into, next etc.
https://github.com/deivid-rodriguez/pry-byebug
Bug Found
Using pry-byebug it's immediatelly clear what's the bug, even though I don't really understand your code because those numbers are meaningless to me.
For first letter it increments j in second condition if( plainTex[j] > 64) and (plainTex[j] < 91 ). Then with incremented j it moves to if( plainTex[j] > 94) and (plainTex[j] < 123) where it increments it again.
You should use elsif for all of these or next
Code Cleanup
Ruby convention is to use snake case to name your variable and I'd change this piece of code:
if( plainTex[j] > 64) and (plainTex[j] < 91 )
if( (plainTex[j] + key) > 91)
ciphTex[j] = (plainTex[j] + key ) - 90
j += 1
else
ciphTex[j] = plainTex[j] + key
j += 1
end
end
to this:
if plain_text[j].between?(65, 90)
ciph_text[j] = plain_text[j] + key
ciph_text[j] -= 90 if ciph_text[j] > 91
j += 1
end
It seems that you are repeating j += 1 in every condition, so why not remove it outside if/else blocks and put it as last line before the loop end?
Also I am a human and I don't want to remember that "A" is 65 and "Z" is 90. Why not say so in the code?
if plain_text[j].between?("A".ord, "Z".ord)
I have never messed with ASCII in ruby, but I am sure you could further improve this, possibly do entire cypher in one simple loop with 10 lines of code or less.
Ruby is really good at processing arrays, so use that. I'd do something like this:
plain_text = text.codepoints
cyph_text = plain_text.map do |code|
if code == ' '.ord
' '.ord
elsif
# return cypher code
end
end
Check out how map function works.

Nuances of where to define a variable in ruby code

I've just started learning ruby, and the position of where variables are defined somewhat elude me. For example, why does this code work:
def two_sum(nums)
result = nil
i = 0
while i < nums.length
k = (nums.length - 1)
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
And why does this code not work:
def two_sum(nums)
result = nil
i = 0
k = (nums.length - 1)
while i < nums.length
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
Thank you in advance!
I think you code might just have a bug
while i < nums.length
k = (nums.length - 1)
...
k -= 1 # this statement has no effect!
end
Above, the value if k is always (nums.length - 1) because you reassign it at the begin of each iteration. The other statement has no effect.
k = (nums.length - 1)
while i < nums.length
...
k -= 1
end
Above, the value of k starts at (nums.length - 1) in the first iteration and is then reduced by 1 for each iteration.
Pro tipp —
It is very unusual in Ruby to use a for/while/until loop. If you want to loop over all elements use each or each_with_index instead
array.each { |each| ... }
array.each_with_index { |each, n| ... }

How to I make floyd triangle shape using for loop?

I need output of Floyd triangle like:
1
0 1
1 0 1
0 1 0 1
I tried. I didn't get it exactly. Can anyone explain the logic?
This is the code I tried:
k = 0
for i in 1..5
for j in 1..5
if (i%2)==0;
k = (j%2==0) ? 1:0;
else;
k = (j%2==0) ? 0:1;
puts k,'';
end
end
puts
end
The main issue here is that in order to get the "triangle" shape of your output, you need your inner loop to increment from 1 to i instead of 1 to 5.
k = 0
for i in 1..5
for j in 1..i
if (i%2)==0
k = j + 1
else
k = j
end
print "#{k%2} "
end
puts
end
Here's a one line approach:
5.times {|line| puts (line + 1).times.with_object(""){|num, str| (num + line).even? ? (str << " 1 ") : (str << " 0 ") } }
to make it more clear:
lines = 5
lines.times do |line|
str = ""
line = line + 1 # 5.times runs from 0 to 4 and we need 1 to 5
line.times do |num|
# the condition is a bit different because I changes the code a bit
if (line + num).even?
str << " 0 "
else
str << " 1 "
end
end
puts str
end
Alright the following should work, but i hope it's readable. If you need more explanation or have specific questions let me know
i = 1
while i <= 4 do
if i%2 > 0
output = 1
else
output = 0
end
j = 1
while j <= i do
print( "#{output} " )
if output == 1
output = 0
else
output = 1
end
j+=1
end
print( "\n" )
i+=1
end
You can try following code for output you are expecting:
k = 0
for i in 1..4
for j in 1..i // inner loop code runs i times for each outer loop iteration
if (i%2)==0;
k = (j%2==0) ? 1:0;
else;
k = (j%2==0) ? 0:1;
end
print k,' ';
end
puts
end
Click Here to see output.
You can also get idea about for loops through this link.
The prefered ruby way:
layers = 4 # Change to as many layers as you want
layers.times do |i| # i starts from 0
(i + 1).times do |j| # j also starts from 0
print (i + j + 1) & 1, ' '
end
puts
end
The for way:
layers = 4
for i in 0...layers
for j in 0...(i + 1)
print (i + j + 1) & 1, ' '
end
puts
end

Getting a 'nil:Nil Class' error in Ruby, but the array doesn't seem to empty

I'm trying to code the 'Sieve of Eratosthenes' in Ruby and I'm having difficulty in the second 'while' loop. I want to test to see if integers[j] % integers[0] == 0, but the compiler keeps giving me a nil:Nil Class error at this line. I can't figure out the problem.
n = gets.chomp.to_i
puts
while n < 2
puts 'Please enter an integer >= 2.'
puts
n = gets.chomp.to_i
puts
end
integers = []
i = 0
while i <= n - 3
integers[i] = i + 2
i += 1
end
primes = []
j = 1
while integers != []
primes.push integers[0]
while j <= integers.length
if integers[j] % integers[0] == 0
integers.delete(integers[j])
end
j += 1
end
integers.shift
j = 1
end
puts integers
puts
puts primes
Thanks in advance for any help!
It's an off-by-one error. You're testing for j <= integers.length. So, for example, if you array has five items, the last iteration will be integers[5]. But the last index in a five-item array is 4 (because it starts at 0). You want j < integers.length.

Brainteaser Locker Open or Closed? in Ruby

Trying to code the classic brainteaser locker problem (the one where you open/close 100 lockers). When I run the code I wrote it does not give me the correct answer of 10 open lockers, but instead says all lockers are closed. I think I'm missing something in my loops...any suggestions? Thanks.
def lockerproblem
j = 0
lockers = []
while j < 100
lockers << "open"
j += 1
end
a = 1
i = 0
while a <= 100
while i < 100
if ( i + 1 ) % a == 0
if lockers[i] == "open"
lockers[i] = "closed"
else
lockers[i] = "open"
end
end
i += 1
end
a += 1
end
lockers[3] = "open"
lockers.each do |text|
puts text
end
end
lockerproblem
Consider this for array initialization:
lockers = ["open"] * 100
Think about your i variable: when is it set to 0? What will that mean to the inner loop? E.g.,
a, b = 0, 0
while a < 2
while b < 2
puts "a=#{a}, b=#{b}"
b += 1
end
a += 1
end
Outputs:
a=0, b=0
a=0, b=1
In other words, you don't see:
a=0, b=0
a=0, b=1
a=1, b=0
a=1, b=1
Why? Because b is incremented to 2, is never reset, and the inner loop only executes once. Perhaps you are setting the initial value of i in the wrong place, where "wrong" means "outside the outer loop".
Lastly, opening the fourth locker (locker[3]) will throw off the results.
There are a number of small tweaks that could make the code a bit easier to understand (heck I might even define an open? method on String for the purposes of this small example), but this should be enough to get you the answer you expect.
Such monkey-patching isn't always a good idea, particularly on Ruby internals. But it allows some easy and nice-looking stuff like this:
> lockers.find_all(&:closed?).size
=> 10
You can get the right answer by making three changes:
i needs to be reset to 0 at the start of each iteration of a
The lockers should start as closed
Remove the extra lockers[3] = "open" line
The updated code:
def lockerproblem
j = 0
lockers = []
while j < 100
lockers << "closed"
j += 1
end
a = 1
i = 0
while a <= 100
i = 0
while i < 100
if ( i + 1 ) % a == 0
if lockers[i] == "open"
lockers[i] = "closed"
else
lockers[i] = "open"
end
end
i += 1
end
a += 1
end
lockers.each do |text|
puts text
end
end
lockerproblem

Resources