Daniel Lee
Daniel Lee

Reputation: 51

What's the difference between 'each...do' and 'do'

Just working on some practice problems but I'm confused what 'do' does exactly

self.length.times do |i|

What would the difference be between this code and

self.each do |i|

Upvotes: 4

Views: 331

Answers (6)

justapilgrim
justapilgrim

Reputation: 6872

The difference is the value of i.

["one", "two", "three"].length.times do |i|
  puts i
end

0
1
2

and the other:

["one", "two", "three"].each do |i|
  puts i
end

one
two
three

As you can see, one returns the index of the loop, and the other the array item.

Upvotes: 1

dom
dom

Reputation: 444

I think it is also good to say, how it actually works.

Let's have code

# could be also defined as with_env_variable_set_to_hello(&block)
def with_env_variable_set_to_hello
   fail ArgumentError unless block_given?

   origin = ENV['MY_VARIABLE']
   ENV['MY_VARIABLE'] = 'hello'
   yield # runs block here
   ENV['MY_VARIABLE'] = origin
end

Usage:

with_env_variable_set_to_hello do
   puts ENV['MY_VARIABLE'] # hello
end

Sometimes, you can use arguments passed to block, such like

items.each do |item|
  # do something
end

It is provided by giving argument to yield (&block)

def do_something
  yield 'arg1', :arg2, 3
end

Usage:

do_something do |string, symbol, integer|
  puts string, symbol, integer # 'arg1' :arg2 3
end

Upvotes: 0

ArtuX
ArtuX

Reputation: 374

Both

self.each do |i|

and

self.length.times do |i|

are not valid Ruby.

In Ruby do is a keyword that starts a block. It must be followed by end keyword which ends a block. Here is a good article you can read about blocks, and how they relate to other similar Ruby constructs, like Procs and Lambdas.

Upvotes: 0

iGian
iGian

Reputation: 11183

I'd like to post a couple of example.

Let's say self object is an Array:

self_object = ['a', 'b', 'c']


With the former option self_object.length.times do |i| you are calling Array#length, which returns the Integer3 and then calling Integer#times on the integer 3 (3.times). This is the result:

self_object.length.times do |i|
  p i
end

# 0
# 1
# 2


With the last option you are just calling Array#each on the array, so:

self_object.each do |i|
  p i
end

# "a"
# "b"
# "c"


each method applies to these objects (see docs):

  • ARGF,
  • Array,
  • Dir,
  • Enumerator
  • Enumerator::ArithmeticSequence,
  • Enumerator::Chain
  • Hash
  • IO
  • ObjectSpace::WeakMap
  • Range
  • Struct

Upvotes: 1

Holger Just
Holger Just

Reputation: 55758

do ... end code blocks (or mostly equivalent { ... } blocks) in Ruby are an important language feature which allow you to pass some behavior (i.e. some block of code) to a method. If you known Javascript, you can think of Ruby's blocks a bit like an anonymous function as a first approximation.

Now, when passing a block to the each method, it will call the block once for each element in the enumeration, passing thew current element as the first argument of the block.

The Integer#times method also takes a block. It will call the block n times with a number as a argument, counting from 0 until n - 1 (with n being whatever number you call the times method on. Thus, the block will be called exactly n times.

Since blocks are an integral part of Ruby which is used about everywhere, you should try to get a good understanding of how they work. You will find a lot of guides and posts on Google if you search fir "ruby blocks".

Upvotes: 3

khelwood
khelwood

Reputation: 59112

With

self.length.times do |i|

i is just counting up numbers between 0 and self.length - 1.

With

self.each do |i|

i will take the value of each element of self.

Upvotes: 0

Related Questions