Difference Between Each.With_Index and Each_With_Index in Ruby

Use case of each_with_index vs index in Ruby

Let's take a closer look at your code:

field=[[1,0],[0,0]]
coordindates = []
field.each_with_index do |item|
if item.index(1)
coordinates.push(field.index(item)).push(item.index(1))
end
end

Let:

enum = field.each_with_index
#=> #<Enumerator: [[1, 0], [0, 0]]:each_with_index>

As you see this returns an enumerator.

Ruby sees your code like this:

enum.each do |item|
if item.index(1)
coordinates.push(field.index(item)).push(item.index(1))
end
end

The elements of the enumerator will be passed into the block by Enumerator#each, which will call Array#each since the receiver, field is an instance of the class Array.

We can see the elements of enum by converting it to an array:

enum.to_a
#=> [[[1, 0], 0], [[0, 0], 1]]

As you see, it has two elements, each being an array of two elements, the first being an array of two integers and the second being an integer.

We can simulate the operation of each by sending Enumerator#next to enum and assigning the block variables to the value returned by next. As there is but one block variable, item, we have:

item = enum.next
#=> [[1, 0], 0]

That is quite likely neither what you were expecting nor what you wanted.

Next, you invoke Array#index on item:

item.index(1)
#=> nil

index searches the array item for an element that equals 1. If it finds one it returns that element's index in the array. (For example, item.index(0) #=> 1). As neither [1,0] nor 0 equals 1, index returns nil.

Let's rewind (and recreate the enumerator). You need two block variables:

field.each_with_index do |item, index|...

which is the same as:

enum.each do |item, index|...

So now:

item, index = enum.next
#=> [[1, 0], 0]
item #=> [1, 0]
index #=> 0

and

item.index(1)
#=> 0

I will let you take it from here, but let me mention just one more thing. I'm not advocating it, but you could have written:

field.each_with_index do |(first, second), index|...

in which case:

(first, second), index = enum.next
#=> [[1, 0], 0]
first #=> 1
second #=> 0
index #=> 0

Ruby : Choosing between each, map, inject, each_with_index and each_with_object

A more tl;dr answer:

How to choose between each, map, inject, each_with_index and each_with_object?

  • Use #each when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:

    numbers.each { |number| puts number.abs }
  • Use #map when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:

    numbers.map { |number| number ** 2 }
  • Use #inject when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:

    numbers.inject(&:+)
  • Use #each_with_index in the same situation as #each, except you also want the index with each element:

    numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
  • Uses for #each_with_object are more limited. The most common case is if you need something similar to #inject, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):

    numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }

Each with index with object in Ruby

From ruby docs for each_with_object

Note that you can’t use immutable objects like numbers, true or false
as the memo. You would think the following returns 120, but since the
memo is never changed, it does not.

(1..5).each_with_object(1) { |value, memo| memo *= value } # => 1

So each_with_object does not work on immutable objects like integer.

Rails each_with_index descend order in index

<%= @objects.length - 1 - i %> - <%= object %><br>

this will substract the index of the length of the array, giving the desired output.

You have to always substract one from the length since a array with length 3 has indexes 0, 1, 2

each_with_index_do starting at 1 for index

I think maybe you misunderstand each_with_index.

each will iterate over elements in an array

[:a, :b, :c].each do |object|
puts object
end

which outputs;

:a
:b
:c

each_with_index iterates over the elements, and also passes in the index (starting from zero)

[:a, :b, :c].each_with_index do |object, index|
puts "#{object} at index #{index}"
end

which outputs

:a at index 0
:b at index 1
:c at index 2

if you want it 1-indexed then just add 1.

[:a, :b, :c].each_with_index do |object, index|
indexplusone = index + 1
puts "#{object} at index #{indexplusone}"
end

which outputs

:a at index 1
:b at index 2
:c at index 3

if you want to iterate over a subset of an array, then just choose the subset, then iterate over it

without_first_element = array[1..-1]

without_first_element.each do |object|
...
end

What's i in each_with_index block

Some methods that are called with code blocks will pass more than one value to the block, so you end up with multiple block arguments (in your case the block arguments are n and i, which will hold the current item in the array (n) and the index of it (i)).

You can find out how many arguments a block will be passed by looking at the documentation for a method (here's the docs for each_with_index). It does look like the extra values come from nowhere at first, and it takes a little while to memorize what a block will be passed when different methods are called.

Ruby using each_with_index

You can build the output string at first, and puts it once it is ready:

input = ["Logan", "Avi", "Spencer"]

def line (katz_deli)
if katz_deli.count > 1
output = "The line is currently:"
katz_deli.each_with_index do |name, index|
output << " #{index +1}. #{name}"
end
puts output
else
puts "The line is currently empty."
end
end

line(input)


Related Topics



Leave a reply



Submit