Array#Each Vs. Array#Map

Array#each vs. Array#map

Array#each executes the given block for each element of the array, then returns the array itself.

Array#map also executes the given block for each element of the array, but returns a new array whose values are the return values of each iteration of the block.

Example: assume you have an array defined thusly:

arr = ["tokyo", "london", "rio"]

Then try executing each:

arr.each { |element| element.capitalize }
# => ["tokyo", "london", "rio"]

Note the return value is simply the same array. The code inside the each block gets executed, but the calculated values are not returned; and as the code has no side effects, this example performs no useful work.

In contrast, calling the array's map method returns a new array whose elements are the return values of each round of executing the map block:

arr.map { |element| element.capitalize }
# => ["Tokyo", "London", "Rio"]

How are array.each and array.map different?

The side effects are the same which is adding some confusion to your reverse engineering.

Yes, both iterate over the array (actually, anything that mixes in Enumerable) but map will return an Array composed of the block results while each will just return the original Array. The return value of each is rarely used in Ruby code but map is one of the most important functional tools.

BTW, you may be having a hard time finding the documentation because map is a method in Enumerable while each (the one method required by the Enumerable module) is a method in Array.

As a trivia note: the map implementation is based on each.

JavaScript: Difference between .forEach() and .map()

They are not one and the same. Let me explain the difference.

forEach: This iterates over a list and applies some operation with side effects to each list member (example: saving every list item to the database) and does not return anything.

map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (example: transforming list of strings to uppercase). It does not mutate the array on which it is called (although the callback function may do so).

References

Array.prototype.forEach() - JavaScript | MDN

Array.prototype.map() - JavaScript | MDN

Why is #map more efficient than #each?

In both of your examples, the second piece of code allocates 100 times as much memory as the first piece of code. It also performs approximately log_1.5(100) resizes of the array (assuming a standard textbook implementation of a dynamic array with a growth factor of 1.5). Resizing an array is expensive (allocating a new chunk of memory, then an O(n) copy of all elements into the new chunk of memory). More generally, garbage collectors hate mutation, they are much more efficient at collecting lots of small short-lived objects than keeping alive a few large long-lived objects.

In other words, in the first example, you are measuring Array#map and Array#select, respectively, whereas in the second example, you are not only measuring Array#each, but also Array#<< as well as array resizing and memory allocation. It is impossible to tell from the benchmarking results, which of those contributes how much. As Zed Shaw once put it: "If you want to measure something, then don't measure other shit".

But even if you fix that bug in your benchmark, generally speaking more specialized operations have more information available than general ones, so the more general operations can typically not be faster than the specialized ones.

In your specific example it may just be something very simple such as, you are using a Ruby implementation that is not very good at optimizing Ruby code (such as YARV, and unlike e.g. TruffleRuby) while at the same time have an optimized native implementation of Array#map and Array#select (again, take YARV as an example, which has C implementations for both of those, and is generally not capable of optimizing Ruby code very well).

And lastly, writing correct microbenchmarks is hard. Really, really, really hard. I encourage to read and understand this entire discussion thread on the mechanical-sympathy Mailing list: JMH vs Caliper: reference thread. While it is specifically about Java benchmarking (actually about JVM benchmarking), many of the arguments apply to any modern high-performance OO execution engine such as Rubinius, TruffleRuby, etc. and to a lesser extent also to YARV. Note that most of the discussion is about writing microbenchmark harnesses, not writing microbenchmarks per se, i.e. it is about writing frameworks that allow developers to write correct microbenchmarks without having to know about that stuff, but unfortunately, even with the best microbenchmark harnesses (and Ruby's Benchmark is actually not a very good one), you still need to have a very deep understanding of modern compilers, garbage collectors, execution engines, CPUs, hardware architectures, but also statistics.

Here is a good example of a failed benchmark that may not be obvious to the untrained benchmark writer: Why is printing “B” dramatically slower than printing “#”?.

Difference in output with map and each

Because Array#each returns the receiver itself. But Array#map, maps, each current character, you passed to the block, with the current computation result.

With #map, the condition if char =~ /[A-Za-z]/ evalutated as falsy, for each passed element like " ". Thus block mapped nil while it founds " " or any element for which if condition evaluated as falsy. But #each forgets about the block result after each iteration is completed, But #map doesn't.

If you look at the output, you can see all nil(s) are in the same position of " ". This observation also dictates about the behaviour I just mentioned above.

In Ruby, every block of code, like definition of class, method definitions, block definitions returns its last statement. In your #map block, there is no statements, after the if modifier, so it reruns nil.

In Ruby >= 2.1.1 I saw method to returns its names as a symbol. But when you will invoke it, then it will return its last statement. If the method body is empty, then nil.

Look below :-

[1] pry(main)> def foo
[1] pry(main)* end
=> :foo
[2] pry(main)> foo
=> nil
[3] pry(main)> def baz
[3] pry(main)* 12
[3] pry(main)* end
=> :baz
[4] pry(main)> baz
=> 12

update

From the comment of @asquirrel, I got an idea. You could write your code a more Ruby way :-

"This is an awesome string".gsub(/[a-z]/i).map(&:next)
# => ["U", "i", "j", "t", "j", "t", "b", "o", "b",
# "x", "f", "t", "p", "n", "f", "t", "u", "s", "j", "o", "h"]

update1

j = "This is an awesome string"

array = j.split('').map do |char|
char =~ /[A-Za-z]/ ? char.next : char
end

p array

# >> ["U", "i", "j", "t", " ", "j", "t", " ", "b", "o", " ", "b",
# "x", "f", "t", "p", "n", "f", " ", "t", "u", "s", "j", "o", "h"]

Does `map` use `each` or not?

Enumerable's implementation of map does use each, but there's nothing stopping an extending class from overriding it with its own implementation that does not use each.

In this case Array does provide its own implementation of map for efficiency reasons.

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 }

what's different between each and collect method in Ruby

Array#each takes an array and applies the given block over all items. It doesn't affect the array or creates a new object. It is just a way of looping over items. Also it returns self.

  arr=[1,2,3,4]
arr.each {|x| puts x*2}

Prints 2,4,6,8 and returns [1,2,3,4] no matter what

Array#collect is same as Array#map and it applies the given block of code on all the items and returns the new array. simply put 'Projects each element of a sequence into a new form'

  arr.collect {|x| x*2}

Returns [2,4,6,8]

And In your code

 a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K 

a is an Array but it is actually an array of Nil's [nil,nil,nil] because puts x.succ returns nil (even though it prints M AA K).

And

 b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K

also is an Array. But its value is ["L","Z","J"], because it returns self.

How to split up an array into a multi-dimensional array

You should use Enumerable#map, because Enumerable#each will just iterate through the items, but #map will create a new array from the return value of the block:

parsed_data.map { |data| data.split(',') }

Why does array.each behavior depend on Array.new syntax?

This is a common misunderstanding. In your first example you are creating an array with 2 elements. Both of those are a pointer to the same array. So, when you iterate through your outer array you add 2 elements to the inner array, which is then reflected in your output twice

Compare these:

> array = Array.new(5, [])
=> [[], [], [], [], []]

# Note - 5 identical object IDs (memory locations)
> array.map { |o| o.object_id }
=> [70228709214620, 70228709214620, 70228709214620, 70228709214620, 70228709214620]

> array = Array.new(5) { [] }
=> [[], [], [], [], []]

# Note - 5 different object IDs (memory locations)
> array.map { |o| o.object_id }
=> [70228709185900, 70228709185880, 70228709185860, 70228709185840, 70228709185780]


Related Topics



Leave a reply



Submit