Reputation: 6349
Often when programming in Ruby, I find myself writing small for loops with a single statement in the body. For example...
for number in 1..10
puts number
end
In other languages like C
, Java
or Kotlin
(for example), I'd be able to write the same code in two lines. For example...
// Kotlin
for (number in 1..10)
println(number)
In the above example, the ending of the loop body is inferred due to the lack of curly braces.
Does Ruby have a way to imitate this "single-statement" style of "for loop"?
Here are some of [my options/your potential replies], along with my thoughts on them.
You could append
; end
to the body to end it on the same line.
This is true, and pretty sufficient, but I'd like to know if there's a more idiomatic approach.
This seems unnecessarily picky. Why would you ever want to do this?
You may think I'm being too picky. You may also think what I'm trying to do is un-idiomatic (if that's even a word). I totally understand, but I'd still love to know if it's do-able!
Doing this could let us write code that's even just a tiny bit nicer to read. And for programmers, readability matters.
Upvotes: 3
Views: 2466
Reputation: 369428
There is a vanishingly tiny number of cases, where any self-respecting Ruby programmer would even write an explicit loop at all. The number of cases where that loop is a for
loop is exactly zero. There is no "more idiomatic" way to write a for
loop, because for
loops are non-idiomatic, period.
Upvotes: 2
Reputation: 27793
There is an even shorter syntax.
If you are just calling one method on each object you can use &
syntax.
(1..3).collect(&:odd?) # => [true, false, true]
This is the same as
(1..3).collect { |each| each.odd? } # => [true, false, true]
This is the preferred way of writing loops in Ruby.
You'll quickly get used to both &
and {}
block syntax and the enumeration methods defined in Enumerable
module. Some useful methods are
each
which evaluates the block for each elementcollect
which create new array with the result from each block detect
which returns the first element for which block results trueselect
which create new array with elements for which block results trueinject
which applies "folding" operation, eg sum = (1..10).inject { |a, b| a + b }
Fun fact, style guides for production code usually ban for
loops at all because of a subtle but dangerous scoping issue. See more here, https://stackoverflow.com/a/41308451/24468
Upvotes: 2
Reputation: 52357
Sure, you're looking for each
, Range#each
in this particular case:
(1..10).each { |number| puts number }
For more complex iterations use do
- end
block syntax. For example
(1..10).each do |number|
puts number
some_method_call(number)
Rails.logger.info("The #{number} is used")
something_else
end
To find more check out Ruby documentation, in particular, see Enumerable.
Upvotes: 9