In Ruby, which means to return an enumerable,

I am trying to understand the following Ruby code:

digits.each_with_index.inject(0) do |decimal, (digit, index)|
      decimal + digit * 2**index


(For reference, digits

this is a method that returns an array where each element is an integer.)

The piece of code that is confusing me is .each_with_index.inject(0)

. I know what a method does each_with_index

and I know what a method does inject

, but I'm not sure how chaining both works together. What exactly is going on?

I tried looking at the documentation for each_with_index

, and I think I have a problem: "If no block is specified, the enumerator returns."

I think it all boils down to what is an enumerator?


source to share

2 answers

An Enumerator abstracts the idea of ​​enumeration so that you can use all the convenience methods Enumerable

without worrying about what the underlying data structure is.

For example, you can use an enumerator to create an object that acts like an infinite array:

squares = do |yielder|
  x = 1
  loop do
    yielder << x ** 2
    x += 1

# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# don't wait up for this one!


The eyewitness to enumerations is that they are enumerated themselves, and most methods Enumerable

return enumerating elements if you don't give them a block. This is what allows you to chain method calls to get one big counter.

This is how I would code each_with_index

so that it can be hooked nicely:

class Array
  def my_each_with_index &blk
    e = do |yielder|
      i = 0
      each do |x|
        yielder << [x, i]
        i += 1

    return e unless blk

[3,2,1].my_each_with_index { |x, i| puts "#{i}: #{x}" }
# 0: 3
# 1: 2
# 3: 1


So first, we create an enumerator that describes how to enumerate the indices. If no block is specified, we simply return the counter. Otherwise, we'll point to an enumerator that enumerates (what it does each

) with a block.



The enumerable is something you might be missing. It is part of Array, Set, etc.

From the docs:

The enumerated mixin provides collection classes with multiple traversal and search methods, and sorting capability. the class must provide each method that yields consecutive members of the Collection. If you are using Enumerable # max, #min, or #sort, the objects in the collection must also implement a meaningful <=> operator, since these methods rely on ordering between collection members.

An enumerator is something you can use later to iterate over: An enumerator is a wrapper class that includes all the methods of Enumarable

In your example code, you enter the default value 0, into each_with_index loop, so in the first loop it decimal

is 0, the digit is the first value of the array and the index is 0. the second time through the loop, decimal is set to the return value of the first pass, the digit is yours the second value of the array and the index is 1.

For example:

digits = [20,30,40]

First time in a loop: decimal = 0, digit = 20, index = 0. This then returns 20.

Second time in the loop: decimal = 20, digit = 30, index = 1. Then 80 is returned.

Third time in the loop: decimal = 80, digit = 40, index = 2. Then 240 is returned.

So this block returns 240.



All Articles