Ruby Tuesday – Enumerable#flat_map

Today’s Ruby Tuesday is on Enumerable#flat_map.

Enumerable#flat_map became this week’s topic, because yesterday I was doing some exercises in Elixir, and was thinking I could use the flat_map that is defined in Elixir to solve the solution, but it wasn’t working the way I thought it should.

I was getting confused with why it was failing, and I went to check my assumptions of how flatmap works in Erlang, and it behaved the same way. Which, after seeing it, is unsurprising given their common runtime, but I couldn’t figure out where my mental model of flat_map was coming from, other than the name alone.

It was time to pull up a Ruby REPL, and see if Ruby was behaving the way I thought it “should” be behaving.

[1, [[2], 3]].flat_map {|x| x * x}
# TypeError: no implicit conversion of Array into Integer
# from (pry):11:in `*'

No! It failed in Ruby as well.

I had myself convinced that flat_map was the equivalent of doing a Array#flatten, and then calling Enumerable#map on the result.

[1, [[2], 3]].flatten.map {|x| x * x}
# [1, 4, 9]

This is the equivalent of what I was trying to get, and flat_map wasn’t working for me, and obviously, it is not the way Enumerable#flat_map behaves either.

After looking deeper, I realized that somehow, I had the application of the conceptual flatten and map methods swapped.

The way Enumerable#flat_map actually behaves is as if you called map on the Enumerable, and then called flatten on the results.

[[:a, 1], [:b, 2], [:c, 3]].flat_map {|item, count| Array.new(count, item) }
# [:a, :b, :b, :c, :c, :c]

[[:a, 1], [:b, 2], [:c, 3]].map {|item, count| Array.new(count, item) }
# [[:a], [:b, :b], [:c, :c, :c]]
[[:a, 1], [:b, 2], [:c, 3]].map {|item, count| Array.new(count, item) }.flatten
# [:a, :b, :b, :c, :c, :c]

And if an Enumerable is not returned by the map block passed to Enumerable#flat_map, it behaves the same as if you just called Enumerable#map.

[1, 2, 3].flat_map {|x| x * x}
# [1, 4, 9]
[1, 2, 3].map {|x| x * x}
# [1, 4, 9]

Here is hoping that this saves you some confusion as well.
–Proctor

1 thought on “Ruby Tuesday – Enumerable#flat_map

  1. Pingback: Erlang Thursday – lists:flatmap/2Proctor It | Proctor It

Comments are closed.