Michael Lubas, 2022-09-14
Write a function in Elixir named build_string
that takes 4 arguments:
a - An integer
b - An integer
ops - A list of the atoms [:add, :sub, :mul, :div] in any order, max length of 10
sep - A separator, such as "-" or ","
and returns a string where a and b are calculated, in-order, together according to the list of operations, delimited by the separator value. For example:
> build_string(8, 2, [:add, :sub], ",")
> "10,6"
> build_string(10, 5, [:div, :sub, :mul, :add], "-")
"2-5-50-15"
Here is an example of bad style:
defmodule Codex do
# Bad style
def build_string(a, b, ops, sep) do
Enum.reduce(ops, "", fn op, acc ->
acc <> sep <> Integer.to_string(calculate(a, b, op))
end)
|> String.trim_leading(sep)
end
def calculate(a, b, op) do
case op do
:add ->
a + b
:sub ->
a - b
:mul ->
a * b
:div ->
div(a, b)
end
end
end
Focus on the build_string/4
function:
def build_string(a, b, ops, sep) do
Enum.reduce(ops, "", fn op, acc ->
acc <> sep <> Integer.to_string(calculate(a, b, op))
end)
|> String.trim_leading(sep)
end
From the start at Enum.reduce
, the accumulator is a blank string, so reduce is creating a string. It is iterating over ops, so the accumulator will be built up in steps:
> build_string(8, 2, [:add, :sub], ",")
> # inside Enum.reduce
> "" <> "," <> "10"
> ",10"
> ",10" <> "," <> "6"
> ",10,6"
Then there is a call to trim the leading sep
, in this case ","
. The call to String.trim_leading/2
here is a red flag that there is a special case in the code evaluation, an additional leading separator value that should not have been introduced.
Now consider this version of build_string/4
:
# Good style
def build_string(a, b, ops, sep) do
ops
|> Enum.map(&calculate(a, b, &1))
|> Enum.join(sep)
end
Enum.map
conveys that calculate/3
transforms every element in the list, preserving the order. Elixir provides Enum.join
, but even if it was not included, writing a function to join all the elements of the list together with a separator value makes this much more clear.
> build_string(8, 2, [:add, :sub], ",")
> [10, 6] # Produced by Enum.map([:add, :sub], &calculate(8, 2, &1))
> "10,6" # Produced by Enum.join([10, 6], ",")
This avoids the problem of building up a string where the leading separator needs to be removed. The problem given may seem trivial, and it is. Making your code as easy to read as possible, by avoiding unnecessary cases, is the important point.
Paraxial.io stops data breaches by helping developers ship secure applications. Get a demo or start for free.
Subscribe to stay up to date on new posts.