The fastest way to iterate a Map’s values in Elixir

Say you have an Elixir Map. What’s the fastest way to iterate the values?

The candidates to consider are:

  • Use and just pick out the values, ignoring the key
  • Use Map.values/1 and pipe the resulting list into

I put together the following Benchfella microbenchmark:

defmodule BasicBench do
  use Benchfella

  @test_map, fn k -> {k, k * k} end)

  bench "Iterate with (anonymous function)" do, fn {_k, v} -> :math.sqrt(v) end)

  bench "Iterate with (capture)" do, &:math.sqrt(elem(&1, 1)))

  bench "Iterate Map.values (anonymous function)" do
  	|> Map.values()
  	|> v -> :math.sqrt(v) end)

  bench "Iterate Map.values (capture)" do
  	|> Map.values()

Here’s what I got running on my 2019 MacBook Pro:

benchmark name                                iterations average time
Iterate Map.values (anonymous function)             5000 385.89 µs/op
Iterate Map.values (capture)                        5000 389.60 µs/op
Iterate with (capture)                     1000 1022.27 µs/op
Iterate with (anonymous function)          1000 1026.64 µs/op

This was surprising to me. Contrary to my intuitions about how Map would be implemented under the hood, grabbing the list of Map.values list was about 2.5× faster than using on the key-value pairs directly.

Also surprising: there’s no difference between the anonymous function and the capture syntax. (I kind of suspected the capture syntax would get optimized differently, but successive runs of the test flip back and forth between the two variants winning.)

TL;DR: Use Map.values/1

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s