Repeat an iteration of an array in ruby - 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

Related

How to modify an iterator while iterating over an array

I want to skip a loop x times according to a condition that is determined at runtime. How can I do this?
for i in (0..5)
if i==0
3.times {next} # i=i+3 also doesnt work
end
puts i
end
Expect to output
3
4
5
EDIT:
To clarify, the question is both the condition (ie i==0) and skipping x times iteration are determined dynamically at runtime, more convoluted example:
condition = Array.new(rand(1..100)).map{|el| rand(1..10000)} #edge cases will bug out
condition.uniq!
for i in (0..10000)
if condition.include? i
rand(1..10).times {next} # will not work
end
puts i
end
simple method to skip by a defined multiple.
array_list = (0..5).to_a
# Use a separate enum object to hold index position
enum = array_list.each
multiple = 3
array_list.each do |value|
if value.zero?
multiple.times { enum.next }
end
begin puts enum.next rescue StopIteration end
end

For loop... Forever

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'

Syntax of loops

I'm trying to iterate a URL to scrape. What am I missing in my syntax?
array = [1...100]
array.each do |i|
a = 'http://www.web.com/page/#{i}/'.scrapify(images: [:png, :gif, :jpg])
extract_images(a[:images])
end
array = [1...100] doesn't do what you think it does. That creates an array with a single element and that single element is a Range instance whose first value is 1 and whose last value is 99.
So, after sorting out your string interpolation problem (as noted elsewhere), this:
"http://www.web.com/page/#{i}/"
will be the string:
"http://www.web.com/page/1...100/"
and the remote server probably doesn't know what that means and it will either 404 or give you page one; your comments elsewhere suggest that it will give you page one and ignore the ...100 part of the URL.
If you want it loop from 1 to 99 then you'd say:
(1...100).each do |i|
# `i` will range from 1 to 99 in this block
end
If you want to loop from 1 to 100 you'd use .. instead of ...:
(1..100).each do |i|
# `i` will range from 1 to 100 in this block
end
You could also ditch the range completely and use times:
99.times do |i|
# `i` will range from 0 to 98 in this block so
# you'd work with `i+1`
end
100.times do |i|
# `i` will range from 0 to 99 in this block so
# you'd work with `i+1`
end
or upto (thanks to JKillian for the reminder about this one):
1.upto(99) do |i|
# `i` will range from 1 to 99 in this block
end
1.upto(100) |i|
# `i` will range from 1 to 100 in this block
end
For interpolation you should use double quotes(" " instead ' '):
array = [1...100]
array.each do |i|
a = "http://www.web.com/page/#{i}/".scrapify(images: [:png, :gif, :jpg])
extract_images(a[:images])
end

Ruby. Range:Each change value

I'm trying to write a siple script, that calculates fibonacci numbers in a loop:
def fib(v)
return v if v < 2
(fib(v-2) + fib(v-1))
end
[0..15].each do |i|
puts "#{fib(i-1)} "
end
But this code fails because i-1 cannot be executed, as i has type Range. What should I do with it? I know, there are many other ways to calculate fibonacci numbers, but I need this code to work, not to rewrite it.
Issue: [] is the syntax for creating an array. So [0..15] creates an array with one element. That one element is the Range, 0..15. Range itself is an enumerable, so you can:
(0..15).each do |i|
puts fibonacci(i - 1)
end
As a side note, using interpolating strings in unnecessary when you have just 1 element to print.

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