New feature Enum.reverse_map

65 views
Skip to first unread message

Robert Dober

unread,
Mar 31, 2019, 11:58:49 AM3/31/19
to elixir-lang-core
Hi there

I do this all the time, travering a reversed list and accumulating a transformation into a new list, unreversed now.

Is this not a very frequent FP pattern.

I would quite happy to use `Enum.reverse_map` which would be more efficent than my eternal internal remimplementation:

```elixir

       defp map_reverse(collection, fun) do                                                                                                                                 
    _map_reverse(collection, fun, [])                                                                                                                                  
  end                                                                                                                                                                  
                                                                                                                                                                       
  defp _map_reverse(collection, fun, result)                                                                                                                           
  defp _map_reverse([], _, result) do                                                                                                                                  
    result                                                                                                                                                             
  end                                                                                                                                                                  
  defp _map_reverse([head|rest], fun, result) do                                                                                                                       
    _map_reverse(rest, fun, [fun.(head)|result])                                                                                                                       
  end
```

Any thoughts?

KR
Robert

Andrea Leopardi

unread,
Mar 31, 2019, 12:01:29 PM3/31/19
to elixir-l...@googlegroups.com
You can do the same in an efficient way with Enum.reduce/3 and prepending to the accumulator:

Enum.reduce(list, [], fn elem, acc ->
  [fun.(elem) | acc ]
end)

I think given this is small and straightforward, an addition of reverse_map to the standard library could be something that we can avoid.

Andrea

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/a4fe903e-9661-448e-ba80-0b8cfc4f8bff%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--

Andrea Leopardi

Robert Dober

unread,
Mar 31, 2019, 12:08:13 PM3/31/19
to elixir-l...@googlegroups.com
Please compare

      coll |> Enum.map_reverse(&my_fun/1)

to

      coll |> Enum.reduce([], fn ele, acc -> [fun(ele)|acc] end)

And also would Enum.map_reverse/2 not be even more optimized, although performance was not my primary motivation.
--
Non datemi consigli che so sbagliare da solo
(Giuseppe Di Stefano)



Andrea Leopardi

unread,
Mar 31, 2019, 12:29:35 PM3/31/19
to elixir-l...@googlegroups.com
We could not optimize the implementation in any significant way (without C code which we don't have in Elixir).

I think that in order to add a new function to Enum, which is already pretty filled up with functions, we would need a few use cases that justify this. Even then, I'm in favour of keeping the API surface smaller and composing with Enum.reduce/3.

Andrea


For more options, visit https://groups.google.com/d/optout.
--

Andrea Leopardi

Tyson Buzza

unread,
Mar 31, 2019, 12:47:10 PM3/31/19
to elixir-lang-core
If optimisation isn't the main goal, what's wrong with just:

coll |> Enum.map(&my_fun/1) |> Enum.reverse()

If you are doing it with a large enough collection that performance becomes an issue look at using Stream. Personally I would do both of these before considering the Enum.reduce form, although my intuition may be off on this one.

Tyson Buzza

unread,
Mar 31, 2019, 12:55:12 PM3/31/19
to elixir-lang-core
Just realised Stream is useless for this use case.

Justin Wood

unread,
Mar 31, 2019, 1:06:13 PM3/31/19
to elixir-l...@googlegroups.com
Is there a reason you are not using List.foldl/3?

List.foldl list, [], (fn elem, acc -> [f(x) | acc] end)

Can I ask why you are reversing a list, traversing it, just to reverse it again?

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐

Robert Dober

unread,
Mar 31, 2019, 3:46:58 PM3/31/19
to elixir-l...@googlegroups.com
I will be perfectly happy w/o an `Enum.map_reverse` and I am completely for a lean interface.

Streams are often a good idea, guess who implemented them for Ruby before they were part of it ;)...

What I felt is that this is kind of a pattern in FP design, so if nobody else feels this itch it certainly is not worth being implemented.

That said, I am a little surprised that nobody clicked on this pattern, but such is life.

Thanx for all the feedback
--
Non datemi consigli che so sbagliare da solo
(Giuseppe Di Stefano)


Robert Dober

unread,
Mar 31, 2019, 3:50:16 PM3/31/19
to elixir-l...@googlegroups.com
as a not related side note, often I do not use `reduce` for that kind of pattern because I feeli

    def treat(list), do: _treat(list, [])
    defp _treat(list, result)
    defp _treat([], result), do: result
    defp _treat([head|tail], result) do
         ...
         treat(tail, ...)
    end
 
is often more readable, but there is no account for taste.

--
Non datemi consigli che so sbagliare da solo
(Giuseppe Di Stefano)


On Sun, Mar 31, 2019 at 7:06 PM 'Justin Wood' via elixir-lang-core <elixir-l...@googlegroups.com> wrote:
Reply all
Reply to author
Forward
0 new messages