I realize this may be against ruby principle and may seem a bit silly, but I am curious to whether it possible to modify the index variable during iteration of a loop in ruby.
This practice is possible in Java/C with the for loop in this contrived example:
for (int k = 0; k < 10; k++)
{
if (k == 5)
k = 8;
}
As well, I am aware that it is possible to access an index variable with Enumerable#each_with_index, but I am interested with the ability to alter the variable in this instance rather than access it.
actually the for semantic is the following:
for(executed_once_before_all; test; execute_every_loop) { /* code */ }
and so, in ruby:
executed_once_before_all
while test do
execute_every_loop
# code
end
so your exemple is like this:
k = 0
while k < 10 do
k = 8 if (k == 5)
k += 1
end
Changing for loop counter in Ruby does not change the number of iterations.
You can change the counter variable, but that will affect the current iteration only:
> for k in 0...10
> k = 8 if k == 5
> puts k
> end
0
1
2
3
4
8 # Note this!
6
7
8
9
The best way to achieve the desired behaviour is to use while loop as #fotanus suggested.
Of course, you can do that with for loop using next statements, but that's much more ugly:
for k in 0...10
next if k > 5 && k <= 8
... do stuff ...
next if k == 5
... do stuff ...
end
You could do that, but Ruby programmers generally don't use the for loop (although it's available). You could also do something like this:
[0,1,2,3,4,5,8,9,10].each do |index|
# your code here
end
Related
How would I do this using ruby and only using a while loop with if, elsif and else only?
sum = 0
i = 1
while i < 251
sum += i
i += 1
end
puts sum
You don’t need a while loop to implement this. But if they want a while loop…
n = 250
while true
puts ( n * (n + 1)) / 2
break
end
Some of the comments have alternatives that are interesting, but keeping this one because it has the flow of control at least pass through the while loop. Not sure if it counts as using a loop if control doesn't even enter the body of the loop.
I initially wrote this in JavaScript, and posted here asking for help (which I got). I then wrote it in Ruby, and it's not working as intended. It looks like the code is pretty much the same in Ruby.
Expected result: 29
Actual result: 2639
prime = 0
temp = 0
factor = 3
i = 3
num = 13195
while factor < num
if num % factor == 0
while i < factor
if factor % i == 0
temp = prime
break
else
temp = factor
end
i = i + 2
end
// i initializes back to 3
// so next factor can properly iterate through loop
i = 3
prime = temp
end
factor = factor + 2
end
i = 3
puts prime
And here's the link to the answer when I asked this as a JavaScript program:
https://stackoverflow.com/a/50970934/7217977
In Javascript, for (let i = 3; i < factor; i += 2) initializes i to 3 and then loops. But in your Ruby code you are initializing i only once at the very beginning, then each of your loops is reusing that one value of i without resetting it back to 3.
The Ruby way of translating that for loop is like this
(3...factor).step(2) do |i|
# loop code
end
this creates a block-local i that is reset for every iteration of the loop and cannot be interfered with by outer scopes.
def num_repeats(string)
letters = string.chars
idx = 0
n = 1
arr = []
lettercount = 0
while idx < letters.length
lettercount = 0
while n < letters.length
if letters[idx] == letters[n]
lettercount = 1
end
n+=1
end
if lettercount > 0
arr.push(idx)
end
idx += 1
end
return arr.length
end
puts(num_repeats("abdbccc"))
# == 2 since 2 letters are repeated across the string of characters
I keep getting zero, although as i see it if a number is repeated the value of numbercount should shift from zero to one and then allow some value to get pushed into the array where I later get the length of said array to determine the number of repeated characters. Is there an issue with my loops?
UPDATE
If you really want to use the same kind of code and algorithm to do that, then here are the problems of it :
In your second while loop the variable n is supposed to start from idx+1, considering you are trying to pick up an index and then find whether the character at that index is repeated somewhere after the index.
But even if you fix that you will get 3 for abdbccc. That kinda shows that your algorithm is wrong. When there are more than 2 occurrences of a repeated character, just like the process I said in the above para, you do that for every such character except for the last one, without checking whether the character had already been detected for repetition. Illustration :
str = 'aaa'
When idx = 0, you get str[idx] == str[n=1], adds it to the result.
When idx = 1, you get str[idx] == str[n=2], adds it to the result.
Now you counted a twice for repetition. I think you can fix that alone.
I think you are just trying to do the same as this (assumes you need to check lower case letters only) :
str = "abdbccc"
('a'..'z').count { |x| str.count(x) > 1 }
# => 2
Or if you need to check the number of repeated characters for any character :
str = "12233aabc"
str.chars.group_by(&:to_s).count do |k, v|
v.size > 1
end
# => 3
It's Ruby we are talking about. It's not really a good idea to write code like that in Ruby, I mean you are using a lot of while loops and manually tracking down their counters, while in Ruby you usually do not have to deal with those, considering all the convenient, less error-prone and shorter alternatives Ruby provides. I think you have a C like background, I recommend that you learn more of Ruby and Ruby way of doing things.
Didn't understood what you were trying to do, maybe you could use a hash to assist:
def num_repeats(string)
letters = string.chars
counter_hash = Hash.new(0)
letters.each { |l| counter_hash[l] += 1 }
counter_hash
end
You have this inner loop
while n < letters.length
if letters[idx] == letters[n]
lettercount = 1
end
n+=1
But nowhere are you resetting n, so after this loop has scanned once, it will skip past every subsequent time
You can mostly fix that by setting n to idx + 1 here
while idx < letters.length
lettercount = 0
n = idx + 1
while n < letters.length
You still will get a result of 3 because you are not detecting that c has already been counted
You can fix this final problem with a couple more tweaks
def num_repeats(string)
letters = string.chars
idx = 0
arr = []
lettercount = 0
while idx < letters.length
lettercount = 0
n = idx + 1 # <== start looking after idx char
while n < letters.length
if letters[idx] == letters[n]
lettercount += 1 # <== incrementing here
end
n+=1
end
if lettercount == 1 # <== check for exactly one
arr.push(idx)
end
idx += 1
end
return arr.length
end
This works because now lettercount == 2 for the first c so the duplicate is not counted until you get to the second c where lettercount == 1
This is still considered a poor solution as it has O(n**2) complexity. There are solutions - for example using Hash which are O(n)
We can do this in Java and similar languages:
for (int i=0, int j=3; i<=2 && j<=5;i++,j++){
do some repetive task until the condition becomes false...
}
How might one keep these two conditions based on two different sets (suppose two
arrays whose indexes can be used as i and j) in condition block?
explicit iteration is kinda looked down upon in ruby as poor expression of thought. Usually there is a better way to achieve the desired goal.
That said, here's is best way I know of to iterate many variables:
i, j, k = 0, 3, 7
while i <= 2 && j <= 5 && k <= 100
# code here
i, j, k = [i, j, k].map(&:next)
end
You can also do it a little messier
i, j = -1, 2
while( (i += 1) <= 2 && (j += 1) <= 5 )
# code here
end
Edit: If you want to go from 0 to 2, and 3 to 5, this works:
(3..5).each_with_index do |j, i|
# code
end
I'm just curious.
Arent both of the code snippets below doing the same thing? Why would someone want to use ... instead of .., wouldnt .. be easier to read?
for x in 1...11
puts x
end
for x in 1..10
puts x
end
Sorry if this is too subjective, I just dont understand why I would want to go from 1 to (n-1) instead of 1 to n
10.5 is included in 1...11, but not in 1..10.
It's not 1 to n vs. 1 to (n - 1), it's 1 <= x <= n vs. 1 <= x < m.
Sometimes the index in some data structure goes form 0 to struct.size() - 1. It's helpful then to have a way of saying this:
a = ['a','b','c']
for i in 0 ... a.length
puts a[i]
end
will print 'a', 'b', 'c'. It you use the .. form it will print an additional nil.
If you use n - 1, then if n is 0, you would have n - 1 of -1, which is used to indicate the end of an array.
array[0...0] # Returns no elements
array[0..-1] # Returns all elements