slouchpie

slouchpie

Efficient use of `reduce`

Imagine I have a simple list

my_list = [1, 2, 3]

and I want to “do something” to each element in a reduce loop, removing elements that error/fail while “doing something”.

It might look like this:

    my_list
    |> Enum.reduce([], fn x, acc ->
      with {:ok, result: result} <- do_something(x) do
        acc ++ [result]
      else
        _ -> acc
      end
    end)

That gets me the result I want.

However, I know that in Elixir it is more efficient to do [result] ++ acc than it is to do acc ++ [result].

So, for large lists, would it be more efficient to use [result] ++ acc in the reduce loop and then in my pipeline use Enum.reverse to put the list back in original order?

Marked As Solved

hauleth

hauleth

Well, in this case I would use Enum.flat_map/2 instead (which behind the hood will do almost the same thing you are doing there with Enum.reverse/1.

Also Liked

NobbZ

NobbZ

The most efficient version to do this is probably doing [result|acc] and Enum.reverse after building the list.

wolf4earth

wolf4earth

Alternatively to Enum.flat_map/2 you can use a for-comprehension:

for with 1-element list

for i <- my_list,
    # We have to wrap the `do_something` call in a list to use `<-` for filtering
    {:ok, result: result} <- [do_something(i)] do
  result
end

for with filter clause

for i <- my_list,
    ok_or_error = do_something(i),
    match?({:ok, _}, ok_or_error) do
  {:ok, result: result} = ok_or_error

  result
end
cloud8421

cloud8421

Note that the compiler actually replaces [hd] ++ acc with [hd | acc] (see https://erlang.org/doc/efficiency_guide/myths.html#myth--operator--++--is-always-bad) so if you try to profile both versions you might not see any difference.

Last Post!

slouchpie

slouchpie

This is equally perfect. Too many solutions 0_o

Where Next?

Popular in Questions Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54921 245
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement