Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

List Benchmarks

notebooks/list_benchmarks.livemd

List Benchmarks

filter_map

Mix.install([:benchee])
defmodule Kore do
  defp custom_filter_map([], _), do: []

  defp custom_filter_map([head | tail], func) do
    case func.(head) do
      false ->
        custom_filter_map(tail, func)

      {true, value} ->
        [value | custom_filter_map(tail, func)]
    end
  end

  def custom_run(list) do
    custom_filter_map(list, fn x ->
      if rem(x, 2) == 0 do
        {true, x * x}
      else
        false
      end
    end)
  end

  def for(list) do
    for x <- list, rem(x, 2) == 0 do
      x * x
    end
  end

  def filter_then_map(list) do
    list
    |> Enum.filter(fn x -> rem(x, 2) == 0 end)
    |> Enum.map(fn x -> x * x end)
  end

  def erlang_filter_then_map(list) do
    list = :lists.filter(fn x -> rem(x, 2) == 0 end, list)
    :lists.map(fn x -> x * x end, list)
  end

  def erlang_filtermap(list) do
    :lists.filtermap(
      fn x ->
        if rem(x, 2) == 0 do
          {true, x * x}
        else
          false
        end
      end,
      list
    )
  end

  def reduce(list) do
    Enum.reduce(list, [], fn x, acc ->
      if rem(x, 2) == 0 do
        [x * x | acc]
      else
        acc
      end
    end)
    |> Enum.reverse()
  end

  def stream_filter_then_map(list) do
    list
    |> Stream.filter(fn x -> rem(x, 2) == 0 end)
    |> Stream.map(fn x -> x * x end)
    |> Enum.to_list()
  end

  def for_uniq(list) do
    for x <- list, uniq: true do
      x.name
    end
  end

  def map_then_uniq(list) do
    list
    |> Enum.map(fn x -> x.name end)
    |> Enum.uniq()
  end
end
max = 10_000
list = Enum.to_list(1..max)

Benchee.run(%{
  "for" => fn ->
    Kore.for(list)
  end,
  "filter.map" => fn ->
    Kore.filter_then_map(list)
  end,
  "erlang filter.map" => fn ->
    Kore.erlang_filter_then_map(list)
  end,
  "erlang filtermap" => fn ->
    Kore.erlang_filtermap(list)
  end,
  "reduce" => fn ->
    Kore.reduce(list)
  end,
  "custom" => fn ->
    Kore.custom_run(list)
  end,
  "stream filter.map" => fn ->
    Kore.stream_filter_then_map(list)
  end
})
employees =
  for _ <- 1..100_000 do
    %{name: Enum.random(["Alice", "Bob", "Carol"])}
  end
Benchee.run(%{
  "for_uniq" => fn ->
    Kore.for_uniq(employees)
  end,
  "map.uniq" => fn ->
    Kore.map_then_uniq(employees)
  end
})
:erlang.system_info(:emu_flavor)

Results filtermap

Max: 10000
Operating System: macOS
CPU Information: Apple M1
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.12.0
Erlang 24.0

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 49 s

Benchmarking custom...
Benchmarking erlang filter.map...
Benchmarking erlang filtermap...
Benchmarking filter.map...
Benchmarking for...
Benchmarking reduce...
Benchmarking stream filter.map...

Name                        ips        average  deviation         median         99th %
reduce                   6.51 K      153.49 μs     ±4.10%         155 μs         165 μs
custom                   5.80 K      172.46 μs     ±3.44%         171 μs         194 μs
for                      5.63 K      177.70 μs     ±9.72%         179 μs         207 μs
erlang filtermap         4.32 K      231.70 μs     ±3.84%         232 μs         260 μs
erlang filter.map        4.11 K      243.60 μs     ±2.09%         244 μs      257.06 μs
filter.map               3.95 K      253.12 μs     ±1.75%         253 μs         268 μs
stream filter.map        1.50 K      665.52 μs     ±8.01%         677 μs         827 μs

Comparison: 
reduce                   6.51 K
custom                   5.80 K - 1.12x slower +18.96 μs
for                      5.63 K - 1.16x slower +24.20 μs
erlang filtermap         4.32 K - 1.51x slower +78.20 μs
erlang filter.map        4.11 K - 1.59x slower +90.11 μs
filter.map               3.95 K - 1.65x slower +99.63 μs
stream filter.map        1.50 K - 4.34x slower +512.03 μs

JIT

Max: 10000
Operating System: macOS
CPU Information: Apple M1
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.12.0
Erlang 25.0-rc0

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 49 s

Benchmarking custom...
Benchmarking erlang filter.map...
Benchmarking erlang filtermap...
Benchmarking filter.map...
Benchmarking for...
Benchmarking reduce...
Benchmarking stream filter.map...

Name                        ips        average  deviation         median         99th %
for                     12.49 K       80.08 μs    ±14.22%       81.99 μs      102.99 μs
reduce                  11.07 K       90.35 μs    ±24.50%       82.99 μs      157.99 μs
erlang filtermap         9.24 K      108.23 μs    ±18.70%      103.99 μs      163.99 μs
custom                   8.95 K      111.79 μs    ±23.80%      100.99 μs      194.91 μs
erlang filter.map        6.45 K      155.03 μs    ±10.42%      149.99 μs      194.99 μs
filter.map               6.32 K      158.28 μs    ±13.42%      149.99 μs      253.99 μs
stream filter.map        2.94 K      339.61 μs    ±14.87%      329.99 μs      478.99 μs

Comparison: 
for                     12.49 K
reduce                  11.07 K - 1.13x slower +10.27 μs
erlang filtermap         9.24 K - 1.35x slower +28.15 μs
custom                   8.95 K - 1.40x slower +31.71 μs
erlang filter.map        6.45 K - 1.94x slower +74.95 μs
filter.map               6.32 K - 1.98x slower +78.20 μs
stream filter.map        2.94 K - 4.24x slower +259.53 μs

Results mapuniq

JIT

Operating System: macOS
CPU Information: Apple M1
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.13.4
Erlang 25.0-rc0

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 14 s

Benchmarking for_uniq ...
Benchmarking map.uniq ...

Name               ips        average  deviation         median         99th %
for_uniq        332.13        3.01 ms     ±5.67%        2.99 ms        3.31 ms
map.uniq        240.29        4.16 ms     ±3.06%        4.14 ms        4.52 ms

Comparison: 
for_uniq        332.13
map.uniq        240.29 - 1.38x slower +1.15 ms