9mm

9mm

Common data transform patterns - please add yours!

So I’m really loving elixir. BY FAR the most excruciating piece of learning a functional language for me is having to “transform” all my input data so that it includes ALL desired output data. In a mutable language like ruby you can have loops and iterators that just update variables (maps, counters, etc) outside the scope. This makes it super easy to wrangle complex data structures… but in Elixir it’s taking me quite awhile to deal with all this.

I wanted to make a little “database” in this thread that I can constantly come back to and reference of all the best ways you might do simple/medium/advanced data transformations. The advanced ones are too many to include in this thread but I feel like there are a lot of simple/medium ones that you can count on 2 hands that you use over and over and over.

I will keep adding to this thread but here are a few to start off…

A. Transform all values inside a map

input: %{a: "hello", b: "world"}
output: %{a: "HELLO", b: "WORLD"}

Answers:

x |> Enum.reduce(%{}, fn {k, v}, acc -> Map.put(acc, k, String.upcase(v)) end)

for({k, v} <- x, into: %{}, do: {k, String.upcase(v)})

:maps.map(fn (_k,v) -> String.upcase(v) end, i)

A2. Transform value inside a map for a specific key

input: %{a: "hello", b: "world"}
output: %{a: "hello", b: "WORLD"}

A3. Transform value for specific key inside a nested map

input: %{person: %{first: "Jose", last: "valim"}, age: 100}
input: %{person: %{first: "JOSE", last: "VALIM"}, age: 100}

Answers:

x |> update_in([:person, :last], &String.upcase(&1))

B. Transform all values inside a list of map

input: [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz}]
output: [%{a: "HELLO", b: "WORLD"}, %{a: "WORLD", b: "BUZZ}]

B2. Transform one value inside a list of map for a specific key

input: [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz}]
output: [%{a: "hello", b: "WORLD"}, %{a: "fizz", b: "BUZZ}]

Answers:

x |> Enum.map(fn m -> Map.update(m, :b, nil, &String.upcase(&1)) end)

C. Push to a list in a map

input: %{list: []}
output: %{list: [1]}

Answers:

x |> update_in([:list], &[1 | &1])

I will add more as I go, feel free to add your own

Most Liked

kokolegorille

kokolegorille

My small contrib for A :slight_smile:

iex> i = %{a: "hello", b: "world"}
iex> o = %{i | a: "HELLO", b: "WORLD"}

# or

iex> o = i |> Enum.reduce(%{}, fn {k, v}, acc -> Map.put(acc, k, String.upcase(v)) end)
peerreynders

peerreynders

input = %{list: []}
output = update_in(input, [:list], &[1 | &1])
IO.inspect(output)
iex(1)> input = %{list: []}
%{list: []}
iex(2)> output = update_in(input, [:list], &[1 | &1])
%{list: [1]}
iex(3)> IO.inspect(output)
%{list: [1]}
%{list: [1]}
iex(4)> 
peerreynders

peerreynders

input = %{person: %{first: "Jose", last: "valim"}, age: 100}
output = update_in(input, [:person, :last], &String.upcase(&1))
IO.inspect(output)
iex(1)> input = %{person: %{first: "Jose", last: "valim"}, age: 100}
%{age: 100, person: %{first: "Jose", last: "valim"}}
iex(2)> output = update_in(input, [:person, :last], &String.upcase(&1))
%{age: 100, person: %{first: "Jose", last: "VALIM"}}
iex(3)> IO.inspect(output)
%{age: 100, person: %{first: "Jose", last: "VALIM"}}
%{age: 100, person: %{first: "Jose", last: "VALIM"}}
iex(4)> 
kokolegorille

kokolegorille

You might also use the into parameters…

iex> output = for({k, v} <- input, into: %{}, do: {k, String.upcase(v)})
peerreynders

peerreynders

input = [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
output = for(m <- input, do: for({k, v} <- m, into: %{}, do: {k, String.upcase(v)}))
iex(1)> input = [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
[%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
iex(2)> output = for(m <- input, do: for({k, v} <- m, into: %{}, do: {k, String.upcase(v)}))
[%{a: "HELLO", b: "WORLD"}, %{a: "FIZZ", b: "BUZZ"}]
iex(3)>   

into is OK as long as you stay with Keyword while you are still transforming the data - i.e. not constantly creating Maps only to turn them back to keywords again.

input = [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
output = Enum.map(input, &(Enum.map(&1, fn {k, v} -> {k, String.upcase(v)} end) |> Map.new()))
iex(1)> input = [%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
[%{a: "hello", b: "world"}, %{a: "fizz", b: "buzz"}]
iex(2)> output = Enum.map(input, &(Enum.map(&1, fn {k, v} -> {k, String.upcase(v)} end) |> Map.new()))
[%{a: "HELLO", b: "WORLD"}, %{a: "FIZZ", b: "BUZZ"}]
iex(3)> 

Where Next?

Popular in Guides/Tuts Top

eclark
I’ve been working on a phoenix project lately and I wanted to use the latest versions of everything. Webpack 5 had some breaking changes ...
New
hauks96
Hello everyone, I created a deployment tutorial for Phoenix applications with Kubernetes (microk8s) a few months back with the goal of s...
New
dkuku
I Created a blog post about setting up svelte with phoenix. I found it a bit tricky and the only blog post I found was written using som...
New
dkuhlman
For those of you who might be interested in using ZeroMQ in Elixir, I converted the Erlang examples in the ZeroMQ “zguide” to Elixir. I ...
New
berts-4865
Here is a quick guide to uploading a file from the browser to DO spaces. It is crude, but will hopefully save sometime time and frustrat...
New
dogweather
I just finished a long process of configuring and debugging a Docker Compose-based dev environment. Several late-night hours! I think I’v...
New
stryrckt
I’m excited about the new LiveComponents feature in LiveView, but I haven’t seen much written on it, so I decided to write a couple of ar...
New
dennisreimann
I wrote a guide for implementing Passwordless Authentication a.k.a. "Magic Login Links": Feedback welcome!
New
anuragg
We just published a guide to automatic clustering in Elixir 1.9, with Mix releases and libcluster. The cluster automatically discovers n...
New
slouchpie
Warmest greetings, comrades. I recently started using :dns_cluster (GitHub - phoenixframework/dns_cluster: Simple DNS clustering for dis...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement