Ruby: loop with index? - ruby

Sometimes, I use Ruby's Enumerable#each_with_index instead of Array#each when I want to keep track of the index. Is there a method like Kernel#loop_with_index I could use instead of Kernel#loop?

loop without a block results in an Enumerator, which has a with_index method (and a each_with_index if you prefer that.)
loop.with_index{|_, i| puts i; break if i>100}

You could use Fixnum#upto with Float::INFINITY.
0.upto(Float::INFINITY) do |i|
puts "index: #{i}"
end
But, I'd probably just use Kernel#loop and keep track of the index myself because that seems simpler.
i = 0
loop do
puts "index: #{i}"
i += 1
end
So, yeah, I don't think there's anything like Kernel#loop_with_index.

In recent Ruby versions, Numeric#step has a default limit of Infinity and a step-size of 1.
0.step{|i| puts i ; break if i>100 }

Related

Can i use a ternary operator instead of while loop

I'm trying to reduce the while loop below to a single line
def this_method(week)
i = 0
while i < array.length
yield(week[i])
i += 1
end
end
week.each do |week|
puts week
end
Like others, I'm confused about the example (array is not defined, and this_method is never called). But you certainly don't need the while loop. I'd just use the Integer#times method, since you're making no use of the array values:
array.length.times {|i| yield week[i]}
#each_index (which ram suggested) works just as well.
But if array is actually meant to be week, then it gets even simpler:
week.each {|x| yield x}
I'm not sure why you'd want to create a method that just recycles #each though.
For since line you can use Array#each_index:
array.each_index {|i| yield week[i] }
No, you can't. The ternary operator is a conditional expression, the while is a loop expression.
However, in Ruby you normally use enumerators, not while. Your code can be rewritten as
def this_method(week)
array.each_with_index { |item, i| yield(week[i]) }
end
What is not clear to me, is there the array variable comes from. Even in your example, there is no definition of such variable.
if in any form check conditions only once.
while on other hand, can check conditions many times.
Well, if you don't like other answers with enumerators you can use while in a different form:
def this_method(week)
i = -1
yield(week[i]) while (i+=1) < array.length
end

Ruby best practice : if not empty each do else in one operator

1.I can't find an elegant way to write this code:
if array.empty?
# process empty array
else
array.each do |el|
# process el
end
end
I'd like to have one loop, without writing array twice. I read this, but there is no solution good enough.
2.
I am actually in an HAML template. Same question.
- if array.empty?
%p No result
- else
%ul
- array.each do |el|
%li el
What about?
array.each do |x|
#...
puts "x",x
end.empty? and begin
puts "empty!"
end
The cleanest way I've seen this done in HAML (not plain Ruby) is something like:
- array.each do |item|
%li
= item.name
- if array.empty?
%li.empty
Nothing here.
As mentioned by other answers, there is no need for the else clause because that's already implied in the other logic.
Even if you could do the each-else in one clean line, you wouldn't be able to achieve the markup you're trying to achieve (<p> if array.empty?, <ul> if array.present?). Besides, the HAML you show in your question is the best way to tell the story behind your code, which means it will be more readable and maintainable to other developers, so I don't know why you would want to refactor into something more cryptic.
I think there is no much more elegant or readable way to write this. Any way to somehow combine an iteration with a condition will just result in blackboxed code, meaning: the condition will just most likely be hidden in an Array extension.
If array is empty, then it will not be iterated, so the each block does not need to be conditioned. Since the return value of each is the receiver, you can put the each block within the empty? condition.
if (array.each do |el|
# process el
end).empty?
# process empty array
end
Assuming that "process empty array" leaves it empty after processing, you can leave out the else:
if array.empty?
# process empty array
end
array.each do |el|
# process el
end
or in one line:
array.empty? ? process_empty_array : array.each { |el| process_el }
An if the array is nil then we can enforce to empty array
if (array || []).each do |x|
#...
puts "x",x
end.empty?
puts "empty!"
end
I saw some people asking how to handle this for nil cases.
The trick is to convert it to string. All nils converted to string becomes a empty string, all empty cases continue being empty.
nil.to_s.empty?
"".to_s.empty?
both will return true

Index count method for iterators in ruby?

When moving over an iteration such as:
array.each do |row|
puts "Current row count: " + row.current_row_index
# do some more stuff
end
Is there a way to get the index of the current iteration / row? Obviously I can just throw in a counter, but I'm curious if there's a shortcut for an index function that shows it's current position.
Been digging through the available methods via pry, however I've not seen anything that seems to do this out of the box.
array.each_with_index |row, index|
puts index
end
If you need exactly the index
array.each_index do |index|
puts index
end

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