For loop... Forever - ruby

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'

Related

Able to use a variable within another variable's name? Ruby

So my goal is to be able to run through a "while" loop and in each iteration create a new variable that includes the "iteration count" within that variables name and stores it for later use outside of the loop. See below for more details.
NOTE: The code is clearly wrong in so many ways but I'm writing it this way to make it more clear? as to what I am trying to accomplish. Thanks for any input on how this is possible.
count = "4"
while count > "0"
player"#{count}"_roll = rand(20)
puts 'Player "#{count}" rolled: "#{player"#{count}"_roll}"'
count -= 1
end
My goal is then to be able to access the variables that were created from within the loop at a later part of the program like so (more or less)
puts player4_roll
puts player3_roll
puts player2_roll
puts player1_roll
The key being that these variables were A) created in the loop B) With names relying on another variables input, and C) accessible outside the loop for later use.
Hopefully my question came out clear and any input will be greatly appreciated. I'm very new to programming and trying to get my head wrapped around some more complex ideas. I'm not sure if this is even possible to do in Ruby. Thanks!
I think the best way is to use arrays or hashes, with arrays its something like this:
count = 0
array = []
while count < 4 do
array[count] = rand(20)
puts "Player #{count} rolled: #{array[count]}"
count += 1
end
array.each do |var|
puts var
end
You store the result in the array and then you loop trough it. If you want the result of the second iteration of the loop you do something like this:
puts array[1]
If you want to use Hashes there are some modifications you need to do:
count = 0
hash = {}
while count < 4 do
hash["player#{count}_roll"] = rand(20)
puts "Player #{count} rolled: #{hash["player#{count}_roll"]}"
count += 1
end
hash.each do |key, var|
puts var
end
If you want the result of the second iteration of the loop you do something like this:
puts hash["player1_roll"]
You could set the variable using instance_variable_set and reference it that way
instance_variable_set("#player#{count}_roll", rand(20))

Repeat an iteration of an array in ruby

Consider I have a loop with a conditional inside, if the condition is true then the current iteration of the loop has to be repeated. For example, consider the following method. Read the note inside the if statement.
def func1(arr)
size = arr.size - 1
max = arr[size]
0.upto(size) do |x|
if (*boolean statement*)
*repeat current iteration*
end
end
func2(arr)
end
How would I go about doing this? In case you are wondering why I need this is because I'm modifying the array such that if the conditional is true for a given x, then the element at index x is removed and placed at the end of the array. If the loop continues then it skips the element after x because this one now has the index of the one removed. In java this is done with the continue keyword I think, is there a ruby equivalent?
Thanks!
Use redo:
def func1(arr)
size = arr.size - 1
max = arr[size]
0.upto(size) do |x|
redo if (*boolean statement*)
end
func2(arr)
end
If I understand your question it seems you simply
need to replace your 'if' conditional with a 'while' one:
def func1(arr)
size = arr.size - 1
max = arr[size]
0.upto(size) do |x|
while (*boolean statement*)
*repeat current iteration*
end
end
func2(arr)
end

Ruby .times .upto .downto, etc. Offsetting the printed value

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}

escaping the .each { } iteration early in Ruby

code:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
I want to grab the first 10 items then leave the "each" loop.
What do I replace the commented line with? is there a better approach? something more Ruby idiomatic?
While the break solution works, I think a more functional approach really suits this problem. You want to take the first 10 elements and print them so try
items.take(10).each { |i| puts i.to_s }
There is no ++ operator in Ruby. It's also convention to use do and end for multi-line blocks. Modifying your solution yields:
c = 0
items.each do |i|
puts i.to_s
break if c > 9
c += 1
end
Or also:
items.each_with_index do |i, c|
puts i.to_s
break if c > 9
end
See each_with_index and also Programming Ruby Break, Redo, and Next.
Update: Chuck's answer with ranges is more Ruby-like, and nimrodm's answer using take is even better.
break works for escaping early from a loop, but it's more idiomatic just to do items[0..9].each {|i| puts i}. (And if all you're doing is literally printing the items with no changes at all, you can just do puts items[0..9].)
Another option would be
items.first(10).each do |i|
puts i.to_s
end
That reads a little more easily to me than breaking on an iterator, and first will return only as many items as available if there aren't enough.
Another variant:
puts items.first(10)
Note that this works fine with arrays of less than 10 items:
>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5
(One other note, a lot of people are offering some form of puts i.to_s, but in such a case, isn't .to_s redundant? puts will automatically call .to_s on a non-string to print it out, I thought. You would only need .to_s if you wanted to say puts 'A' + i.to_s or the like.)
Does this look like what you want?
10.times { |i|
puts items[i].to_s
}
items.each_with_index { |i, c| puts i and break if c <= 9 }
It was asked:
I want to grab the first 10 items then leave the "each" loop.
Use throw and catch to accomplish this, with few changes to the example:
catch(:done) do
c = 0
collected = []
items.each do |item|
collected << item
throw(:done, collected) if c == 9 # started at 0
c += 1
end
collected # if the list is less than 10 long, return what was collected
end
Simply throw the label :done with collected and the catch which is waiting for :done will return collected.
And to "ruby" this up a bit:
catch(:done) do
items.inject([]) do |collected, item|
throw(:done, collected) if collected.size == 10
collected << item # collected gets returned here and populates the first argument of this block
end
end
I do not know why some people refuse to use inject and use reduce instead (they are equivalent) when clearly the empty array given to inject([]) is being injected with items! Anyhow, the inject will return collected if there are less than 10 items.
Most answers are trying to answer what might be the intent of the question instead of what was asked and items.take(10) does make perfect sense in that case. But I can imagine wanting to grab the first items that fit within my $100 budget. Then you can simply:
catch(:done) do
items.inject({items: [], budget: 100}) do |ledger, item|
remainder = ledger[:budget] - item.price
if remainder < 0
throw(:done, ledger)
else
ledger.tap do |this|
this[:items] << item
this[:budget] = remainder
end # tap just returns what is being tapped into, in this case, ledger
end
end
end

Syntax for a for loop in ruby

How do I do this type of for loop in Ruby?
for(int i=0; i<array.length; i++) {
}
array.each do |element|
element.do_stuff
end
or
for element in array do
element.do_stuff
end
If you need index, you can use this:
array.each_with_index do |element,index|
element.do_stuff(index)
end
limit = array.length;
for counter in 0..limit
--- make some actions ---
end
the other way to do that is the following
3.times do |n|
puts n;
end
thats will print 0, 1, 2, so could be used like array iterator also
Think that variant better fit to the author's needs
I keep hitting this as a top link for google "ruby for loop", so I wanted to add a solution for loops where the step wasn't simply '1'. For these cases, you can use the 'step' method that exists on Numerics and Date objects. I think this is a close approximation for a 'for' loop.
start = Date.new(2013,06,30)
stop = Date.new(2011,06,30)
# step back in time over two years, one week at a time
start.step(stop, -7).each do |d|
puts d
end
The equivalence would be
for i in (0...array.size)
end
or
(0...array.size).each do |i|
end
or
i = 0
while i < array.size do
array[i]
i = i + 1 # where you may freely set i to any value
end
array.each_index do |i|
...
end
It's not very Rubyish, but it's the best way to do the for loop from question in Ruby
To iterate a loop a fixed number of times, try:
n.times do
#Something to be done n times
end
If you don't need to access your array, (just a simple for loop) you can use upto or each :
Upto:
2.upto(4) {|i| puts i}
2
3
4
Each:
(2..4).each {|i| puts i}
2
3
4
What? From 2010 and nobody mentioned Ruby has a fine for /in loop (it's just nobody uses it):
ar = [1,2,3,4,5,6]
for item in ar
puts item
end
['foo', 'bar', 'baz'].each_with_index {|j, i| puts "#{i} #{j}"}
Ruby's enumeration loop syntax is different:
collection.each do |item|
...
end
This reads as "a call to the 'each' method of the array object instance 'collection' that takes block with 'blockargument' as argument". The block syntax in Ruby is 'do ... end' or '{ ... }' for single line statements.
The block argument '|item|' is optional but if provided, the first argument automatically represents the looped enumerated item.

Resources