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
Confusion About Passing Instance Variables to Redirect_To Method. as Seen in Rails Guides
How to Dynamically Create a Local Variable in Ruby
Store the Day of the Week and Time
Set Utf-8 as Default for Ruby 1.9.3
How to Simulate Java-Like Annotations in Ruby
Ruby 1.9 Hash with a Dash in a Key
Get Single Char from Console Immediately
How to Check a Word Is Already All Uppercase
Ruby: Accessing Rake Task from a Gem Without Rails
Ruby Source Code Analyzer (Something Like Pylint)
Best Way to Debug Third-Party Gems in Ruby
Rails: Postgres Permission Denied to Create Database on Rake Db:Create:All