Qqwy
Fun with mapping over tuples
During writing some code related to Arrays , I encountered a situation in which I wanted to map a function over a tuple.
Now, code that does this is very easy to write if you know exactly what size of tuple you have.
If you don’t… it becomes a little tedious, as Erlang supports tuples with up to 255 elements (EDIT: Turns out that nowadays it supports tuples with up to 2^24 number of elements…
).
But in Elixir, we can have the code write itself, with some simple metaprogramming:
defmodule TupleMap do
@max_tuple_size 255
def map_tuple({}, _fun), do: {}
def map_tuple({val}, fun), do: {fun.(val)}
def map_tuple({val1, val2}, fun), do: {fun.(val1), fun.(val2)}
# ... etc.
# But writing this by hand is tiresome. So instead:
for index <- 3..@max_tuple_size do
vars = Enum.map(1..index//1, fn index -> Macro.var(:"val#{index}", nil) end)
vars_tuple = {:{}, [], vars}
result_vars =
Enum.map(vars, fn var ->
quote do
unquote(Macro.var(:fun, nil)).(unquote(var))
end
end)
result_tuple = {:{}, [], result_vars}
def map_tuple(unquote(vars_tuple), fun) do
unquote(result_tuple)
end
end
# For comparison:
def map_tuple_through_list(tuple, fun) do
list = Tuple.to_list(tuple)
result_list = :lists.map(fun, list)
List.to_tuple(result_list)
end
end
I ran a small benchmark on this code, for tuples with up to 20 elements (it would definitely be interesting to run a longer benchmark later).
The results are interesting: It seems that mapping over a tuple is ~30%-50% faster than mapping over a list.
The memory usage (not shown in this picture) is also only 1/4th of that of a list.
This benchmark is of course not very scientific, but I still thought it was interesting and something that might be nice to share.
I don’t know how frequent it is to map a function over all elements in a tuple, but if someone wants above code could easily be wrapped up in a library. Or even better: changed into a macro which includes a defp-implementation in a module that needs it, which will then guarantee that the tuple-call is inlined.
EDIT: I couldn’t help myself and have run a larger benchmark: ![]()
Popular in Discussions
Other popular topics
Chat & Discussions>Discussions
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex












