# Writing idiomatic Elixir code

**URL:** <https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365>\
**Category:** Questions\
**Tags:** code-style, idiomatic-elixir\
**Created:** [November 13, 2016, 12:53pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365 "2016-11-13T12:53:29Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![thousandsofthem](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/thousandsofthem/32/1030_2.png) [@thousandsofthem](https://forum.elixirforum.com/u/thousandsofthem)\
**Post date:** [November 13, 2016, 12:53pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/1 "2016-11-13T12:53:29Z")

</div>

Trying to write good elixir code.

Input:

```elixir
data = %{"a" => 0, "b" => 2, "c" => 0, "evilkey" => 666}

```

for specific keys i need to write some specific output if condition is true

Ruby version:

```ruby
out = []
out << "text1" if data["a"] > 0
out << "text2" if data["b"] > 0
out << "text3" if data["c"] > 0
out

```

Ugly elixir version:

```elixir
out = []
out = if data["a"] > 0 do
  out ++ ["text1"]
else
  out
end
...
...
out

```

Good elixir version: ???

Any thoughts here?

---

<div class="post-metadata">

**Author:** ![taiansu](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/taiansu/32/2095_2.png) [@taiansu](https://forum.elixirforum.com/u/taiansu)\
**Post date:** [November 13, 2016, 1:14pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/2 "2016-11-13T13:14:28Z")

</div>

A more functional apporach

```
output_texts = %{
  "a" => "text1",
  "b" => "text2",
  "c" => "text3",
}

out = data
      |> Enum.filter(fn {_, v} -> v > 0 end)
      |> Enum.filter(fn {k, _} -> Enum.member(Map.keys(output_texts), k) end)
      |> Enum.map(fn {k, _} -> output_texts[k] end)
      |> Enum.join()

```

---

<div class="post-metadata">

**Author:** ![michalmuskala](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/michalmuskala/32/20288_2.png) [@michalmuskala](https://forum.elixirforum.com/u/michalmuskala)\
**Post date:** [November 13, 2016, 1:16pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/3 "2016-11-13T13:16:03Z")

</div>

You can do that by using `if` as an expression and assembling list of values finally concatenating them together:

```elixir
IO.iodata_to_binary([
  if(data["a"] > 0, do: "text1", else: ""),
  if(data["b"] > 0, do: "text2", else: ""),
  if(data["c"] > 0, do: "text3", else: "")
])

```

You could even extract the `if` to a separate function, if the pattern if very repeating:

```elixir
defp if_positive(value, text), do: if(value > 0, do: text, else: "")

IO.iodata_to_binary([
  if_positive(data["a"], "text1"),
  if_positive(data["b"], "text2"),
  if_positive(data["c"], "text3")
])

```

---

<div class="post-metadata">

**Author:** ![thousandsofthem](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/thousandsofthem/32/1030_2.png) [@thousandsofthem](https://forum.elixirforum.com/u/thousandsofthem)\
**Post date:** [November 13, 2016, 1:26pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/4 "2016-11-13T13:26:45Z")

</div>

Thanks!

The solution with filters and map look about right.

Re: `IO.iodata_to_binary` thing - i can’t just put things together this way, but overall it looks good, just need to add ` |> Enum.filter(fn(x) -> !is_nil(x) end)`, i.e.

```elixir
[
  (if data["a"] > 0, do: "text1"),
  (if data["b"] > 0, do: "text2"),
  (if data["c"] > 0, do: "text3")
] |> Enum.filter(fn(x) -> !is_nil(x) end)

```

---

<div class="post-metadata">

**Author:** ![benwilson512](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/32/1457_2.png) [@benwilson512](https://forum.elixirforum.com/u/benwilson512)\
**Post date:** [November 13, 2016, 3:55pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/5 "2016-11-13T15:55:03Z")

</div>

```elixir
data
|> Enum.filter(&match?({_, v} when v > 0, &1))
|> Enum.map(fn 
  {"a", _} -> "text1"
  {"b", _} -> "text2"
  {"c", _} -> "text3"
end)

```

---

<div class="post-metadata">

**Author:** ![benwilson512](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/32/1457_2.png) [@benwilson512](https://forum.elixirforum.com/u/benwilson512)\
**Post date:** [November 13, 2016, 3:56pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/6 "2016-11-13T15:56:24Z")

</div>

Also because nobody has mentioned this yet, the “ugly elixir version” is not actually an elixir version. It would not work at all because `out` is immutable.

---

<div class="post-metadata">

**Author:** ![thousandsofthem](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/thousandsofthem/32/1030_2.png) [@thousandsofthem](https://forum.elixirforum.com/u/thousandsofthem)\
**Post date:** [November 13, 2016, 4:21pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/7 "2016-11-13T16:21:26Z")

</div>

It will, there are re-assignment for `out`:

```elixir
out = if ...
  out ++ ...
else
  out
end

```

so every consequent `out` is different variable

---

<div class="post-metadata">

**Author:** ![NobbZ](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nobbz/32/27235_2.png) [@NobbZ](https://forum.elixirforum.com/u/NobbZ)\
**Post date:** [November 13, 2016, 4:56pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/8 "2016-11-13T16:56:51Z")

</div>

We do not have any guarantee of ordering in a map. So in theory the begs pour of this snippet is non deterministic, while in the OPs version we do have an explicit ordering of the keys and their transformation/concatenation into the result.

---

<div class="post-metadata">

**Author:** ![rvirding](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rvirding/32/1409_2.png) [@rvirding](https://forum.elixirforum.com/u/rvirding)\
**Post date:** [November 13, 2016, 5:50pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/9 "2016-11-13T17:50:41Z")

</div>

I know people love `|>` but you don’t have to use it:

```
:maps.fold(fn (k,v,acc) when v > 0 -> acc ++ [output_texts[k]]
              (_,_,acc) -> acc
           end, [], data)

```

There is probably a function equivalent to `fold` in `Enum` but it is called something else and I could not immediately see it, hence using the one in `:maps`.

---

<div class="post-metadata">

**Author:** ![thousandsofthem](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/thousandsofthem/32/1030_2.png) [@thousandsofthem](https://forum.elixirforum.com/u/thousandsofthem)\
**Post date:** [November 13, 2016, 6:23pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/10 "2016-11-13T18:23:33Z")

</div>

Yeah, in my use-case ordering guarantees are required so maps don’t work (but for someone else it could be better approach). also there are other non-related keys as well (which should be filtered out)

plain `[..., ..., ...] |> remove nils` works just fine - ordering granaries, short and easy to read code

---

<div class="post-metadata">

**Author:** ![NobbZ](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nobbz/32/27235_2.png) [@NobbZ](https://forum.elixirforum.com/u/NobbZ)\
**Post date:** [November 13, 2016, 7:02pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/11 "2016-11-13T19:02:37Z")

</div>

It’s called reduce and is a left fold AFAIR

---

<div class="post-metadata">

**Author:** ![rvirding](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rvirding/32/1409_2.png) [@rvirding](https://forum.elixirforum.com/u/rvirding)\
**Post date:** [November 13, 2016, 7:10pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/12 "2016-11-13T19:10:57Z")

</div>

Ah, classic name and not from the functional world. On a map there is no left or right.

---

<div class="post-metadata">

**Author:** ![NobbZ](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nobbz/32/27235_2.png) [@NobbZ](https://forum.elixirforum.com/u/NobbZ)\
**Post date:** [November 13, 2016, 7:39pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/13 "2016-11-13T19:39:43Z")

</div>

I’m aware that we have no left or right in a map but we do have more data structures which in fact do have. And for some operations it is important to know if we are folding from the left or the right.

---

<div class="post-metadata">

**Author:** ![rvirding](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rvirding/32/1409_2.png) [@rvirding](https://forum.elixirforum.com/u/rvirding)\
**Post date:** [November 13, 2016, 8:29pm UTC](https://forum.elixirforum.com/t/writing-idiomatic-elixir-code/2365/14 "2016-11-13T20:29:26Z")

</div>

Yes, for many structures you definitely need to know whether you are folding left or right. That is one reason why calling them `foldl` and `foldr` is better than just `reduce`. The `:maps` module just has `fold` as there is no defined ordering.
