.reduce, .map, .detect methods and using them with .each_with_index

Kevin Kawai
Jul 23, 2017 · 3 min read

Recently I wrote about using ruby blocks to augment the behavior of other methods. Today I will write about some of these methods that I seem to use with blocks very often. These methods are reduce, map and detect. They are all methods that can be used on an array and will output useful information the blocks that they are given.

Reduce
The reduce method goes through an array and evaluates an operation against an accumulator until there are no more elements left. This can be useful to quickly get the sum of an array consisting of only integers. There are two ways to write this method. First you could not use a block and only specify the initial value and operation. If no initial value is specified then the first element in the array is taken as the initial value

ex_arr = [1,2,3,4,5]
ex_arr.reduce(:+)
==> 15

The second way to write the reduce method is to specify a block with a memo value as the accumulator and another value as the element in the array. This is followed by the block and the result of running the block is what the new memo value becomes.

ex_arr = [1,2,3,4,5]
ex_arr.reduce {|memo,value| memo + value}
==> 15

Map
The map method is similar to the reduce method but instead of using an accumulator value it will output an array of the same length as the input array. Map will run through all the elements of the array and apply the block to each one until it reaches the end. Then it will output these values as an array.

ex_arr = [2,4,6,8]
ex_arr.map {|x| x *x}
==> [4, 16, 36, 64]

Detect
As you may have noticed all of these methods go through an array in one way or another. This is the same for the detect method. The detect method goes through an array and runs it against the block it was specified. If the specified returns a truthy statement the loop will break and that value returned. This is useful when you need to check an array for a certain criteria. Note though that this returns the first element that returns true so if an element later does as well it will not return that.

ex_arr = [1,3,5,6,7,9,10]
ex_arr.detect {|x| x.even?}
==> 6

Each_with_index
If for some reason we needed access to the index of the value we are passing we can precede one of the above methods with the each_with_index method to get access to this. This could be useful when you need to compare the current value with another array for some sort of value when you are using map or reduce.
(Check out this challenge on codewars for an example of this type of usage https://www.codewars.com/kata/52761ee4cffbc69732000738)

ex_arr_ref = [1,1,1,2,5,10]
ex_arr = [4,2,6,2,4,1]
ex_arr.each_with_index.reduce(0){|sum,(x,i)|sum + ex_arr_ref[i] * x}
==> 48

In the above code we have two arrays, “ex_arr_ref” is the reference array that holds what each element in the next array should equal. “ex_arr” is an array that holds the quantity of the values. Then we loop through “ex_arr” using the index to refer to the value of each element in the array. In this way we can get the total value of the array compared against the values.

For map we could do something similar but instead of returning the total value we could return an array of what each element would equal when multiply with it’s value

ex_arr_ref = [1,1,1,2,5,10]
ex_arr = [4,2,6,2,4,1]
ex_arr.each_with_index.map{|x,i|ex_arr_ref[i] * x}
==> [4,2,6,6,20,10]
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade