Is there a way to offset the value that has been passed in the code block.
For example
C# - This will always print 5
for (int i = 0; i < 10; i++)
{
i=5
Console.WriteLine(i);
}
Ruby - This will print 5 for only 10 times.
10.times do |i|
i = 5
puts i
end
Is there a way to get |i| to get back to 5?
and another question. How can you make .times block skip(not increasing by 1 all the time)
No, you can't reset the counter of times, upto etc. from within the block.
You can use redo to restart the current iteration of the loop, which in this case will have a similar effect:
10.times do |i|
i = 5
puts i
redo
end
This will print 5 forever (though take note, that the initial value of i will still be 0 at each iteration).
If you need more control than this, you need to use a while loop. Though I'd advice that in most cases where you think you need this, you actually don't and you're just approaching your problem from the wrong angle.
You can use the 'next' keyword to skip iterations based on certain criteria if need be.
10.times do |i|
next if i < 5
puts i
end
Also you may use the keyword 'redo' as described by sepp2k.
This will print the value 5 ten times.
i=5
10.times{puts i}
Related
I have a for loop that I would like to have increment forever.
My code:
for a in (0...Float::INFINITY).step(2)
puts a
end
Output:
0.0
2.0
4.0
Etc. Always with "#{a}.0"
Is there any way to express infinity as an integer, so that the output does not have a .0 at the end without preforming any operations on the contents of the loop?
Addendum
Could you also explain how your loop works? I am trying to find the most efficient solution, because since this loop will be iterating infinity, a few milliseconds shaved off will improve the performance greatly.
Also...
I will accept the solution that takes to shortest time to run to 1000000
According to benchmark both #Sefan and the while loop answers take the same ammount of timeFruity the while loop answers take a bit shorter, with the for loop answers in second, but the multiple loop do answers take far longer.
Since the reason why is out of the scope of this question, I have created another question that addresses why some loops are faster than others (https://stackoverflow.com/questions/33088764/peddle-to-the-metal-faster-loop-faster).
You can use Numeric#step without passing a limit:
0.step(by: 2) { |i| puts i }
Output:
0
2
4
6
...
You can also build your own Enumerator:
step2 = Enumerator.new do |y|
a = 0
loop do
y << a
a += 2
end
end
step2.each { |i| puts i }
You can use while true for that:
puts a = 0
puts a+=2 while true
BTW,
Is there any way to express infinity as an integer
NO
require 'bigdecimal'
(0..BigDecimal('Infinity')).step(2).each{ |n| puts n }
OR
require 'bigdecimal'
for a in (0...BigDecimal::INFINITY).step(2)
puts a
end
This is what the loop method is designed for. loop has no condition for which to run. It will run indefinitely and the only way to exit is to use the keyword break. (or raise a StopIteration)
a = 0
loop { puts a += 2}
This loop will be infinite as there is no break specified.
break can be specified very similarly to how the other answers use the while condition if needed:
a = 0
loop do
puts a += 2
break if a > 1_000_000
end
This loop will now exit once the value of a exceeds 1M.
That being said #Stefan's answer is more efficient as it does not store this integral value or have to perform any additional assignment but rather the number is simply yielded from an Enumerator and discarded it afterwards. The usefulness of this becomes more a matter of your implementation and purpose for this loop.
Try this:
arr = [0]
arr.cycle(1000000) { |i| puts arr[0] +=2 }
If you want infinite loop, then, don't pass any parameter to cycle
arr = [0]
arr.cycle { |i| puts arr[0] +=2 }
a = [-2]
puts a.unshift(a.shift+2) while 'loop forever'
For example, if I want to make a timer, how do I make a delay in the loop so it counts in seconds and do not just loop through it in a millisecond?
The 'comment' above is your answer, given the very simple direct question you have asked:
1.upto(5) do |n|
puts n
sleep 1 # second
end
It may be that you want to run a method periodically, without blocking the rest of your code. In this case, you want to use a Thread (and possibly create a mutex to ensure that two pieces of code are not attempting to modify the same data structure at the same time):
require 'thread'
items = []
one_at_a_time = Mutex.new
# Show the values every 5 seconds
Thread.new do
loop do
one_at_a_time.synchronize do
puts "Items are now: #{items.inspect}"
sleep 5
end
end
end
1000.times do
one_at_a_time.synchronize do
new_items = fetch_items_from_web
a.concat( new_items )
end
end
Somehow, many people think that putting a sleep method with a constant time interval as its argument will work. However, note that no method takes zero time. If you put sleep(1) within a loop, the cycle will surely be more than 1 second as long as you have some other content in the loop. What is worse, it does not always take the same time processing each iteration of a loop. Each cycle will take more than 1 second, with the error being random. As the loop keeps running, this error will contaminate and grow always toward positive. Especially if you want a timer, where the cycle is important, you do not want to do that.
The correct way to loop with constant specified time interval is to do it like this:
loop do
t = Time.now
#... content of the loop
sleep(t + 1 - Time.now)
end
For example, if I want to make a timer, how do I make a delay in the loop so it counts in seconds and do not just loop through it in a millisecond?
The 'comment' above is your answer, given the very simple direct question you have asked:
1.upto(5) do |n|
puts n
sleep 1 # second
end
It may be that you want to run a method periodically, without blocking the rest of your code. In this case, you want to use a Thread (and possibly create a mutex to ensure that two pieces of code are not attempting to modify the same data structure at the same time):
require 'thread'
items = []
one_at_a_time = Mutex.new
# Show the values every 5 seconds
Thread.new do
loop do
one_at_a_time.synchronize do
puts "Items are now: #{items.inspect}"
sleep 5
end
end
end
1000.times do
one_at_a_time.synchronize do
new_items = fetch_items_from_web
a.concat( new_items )
end
end
Somehow, many people think that putting a sleep method with a constant time interval as its argument will work. However, note that no method takes zero time. If you put sleep(1) within a loop, the cycle will surely be more than 1 second as long as you have some other content in the loop. What is worse, it does not always take the same time processing each iteration of a loop. Each cycle will take more than 1 second, with the error being random. As the loop keeps running, this error will contaminate and grow always toward positive. Especially if you want a timer, where the cycle is important, you do not want to do that.
The correct way to loop with constant specified time interval is to do it like this:
loop do
t = Time.now
#... content of the loop
sleep(t + 1 - Time.now)
end
In C and many other languages, there is a continue keyword that, when used inside of a loop, jumps to the next iteration of the loop. Is there any equivalent of this continue keyword in Ruby?
Yes, it's called next.
for i in 0..5
if i < 2
next
end
puts "Value of local variable is #{i}"
end
This outputs the following:
Value of local variable is 2
Value of local variable is 3
Value of local variable is 4
Value of local variable is 5
=> 0..5
next
also, look at redo which redoes the current iteration.
Writing Ian Purton's answer in a slightly more idiomatic way:
(1..5).each do |x|
next if x < 2
puts x
end
Prints:
2
3
4
5
Inside for-loops and iterator methods like each and map the next keyword in ruby will have the effect of jumping to the next iteration of the loop (same as continue in C).
However what it actually does is just to return from the current block. So you can use it with any method that takes a block - even if it has nothing to do with iteration.
Ruby has two other loop/iteration control keywords: redo and retry.
Read more about them, and the difference between them, at Ruby QuickTips.
I think it is called next.
Use next, it will bypass that condition and rest of the code will work.
Below i have provided the Full script and out put
class TestBreak
puts " Enter the nmber"
no= gets.to_i
for i in 1..no
if(i==5)
next
else
puts i
end
end
end
obj=TestBreak.new()
Output:
Enter the nmber
10
1
2
3
4
6
7
8
9
10
Use may use next conditionally
before = 0
"0;1;2;3".split(";").each.with_index do |now, i|
next if i < 1
puts "before it was #{before}, now it is #{now}"
before = now
end
output:
before it was 0, now it is 1
before it was 1, now it is 2
before it was 2, now it is 3
I find the .each do hard to get to stick, so I was hoping for regular use of C for loop syntax which seems to not work, so I tried a while but still get errors.
I have tried this.
i = 0
while i < SampleCount
samples[i] = amplitude
amplitude *= -1
i++
end
I get complaints about the end statement here.
There are several problems with your code. Rather than just fixing the errors, I'd suggest it's better long-term for you to learn the Ruby way - it will save you time and energy later. In this case, it's
5.times do |i|
samples[i] = amplitude # assumes samples already exists and has 5 entries.
amplitude *= -1
end
If you insist on keeping a similar style, you can do this:
samples = []
i = 0
while i < sample_count
samples << amplitude # add new item to array.
amplitude *= -1
i += 1 # you can't use ++.
end
Note that SampleCount's initial capital letter, by Ruby convention, means a constant, which I'm guessing isn't what you really mean.
I agree with Peter that there are other (more idiomatic) ways to do this in Ruby, but just to be clear: the error message you saw misdirected you. There wasn't anything wrong with your while loop per se. The problem was i++ since there is no ++ operator in Ruby.
This would work just fine:
limit = 10
i = 0
while i < limit
puts i
i += 1
end
Again, I'm not recommending it, but if you're just learning the language, it may help to know where the problem really was.
Ruby has a lot of built-in ways to iterate other than for or while (which tend to be seen less often, as far as I can tell). A few other examples:
(1..10).each do |x| # 1..10 is a range which you can iterate over with each
puts x
end
1.upto(10) { |x| puts x } # Integers have upto and downto methods that can be useful
You originally mentioned trying to use a for loop. Notwithstanding the various other comments in the answers, here's the for loop approach:
for i in 0...5
samples[i] = amplitude
amplitude *= -1
end
Nobody here has actually offered an alternate solution that actually does what Fred originally intended - and that's iterate around the value of the constant SampleCount. So could you do:
SampleCount.times do |i|
Or:
limit = SampleCount
limit.times do |i|
Or:
for i in 0..SampleCount
Would any of those be Ruby-esque enough?
The problem with the end statement is related to i++. Ruby wants to add something. There is no increment operator in Ruby. You need to use i += 1. With that change you can use your C style loop as is.