Elixir
I’m currently reading the Programming Elixir book by Dave Thomas, which has been very good so far! Slowly but surely, I’m picking up some Elixir skills. I maybe should start from the beginning sometime soon, but now that I’m starting to blog in the middle of the book, I’ll just start with the current problem, and try to fill in any weird Elixir tricks.
Exercise: ListAndRecursion-2
Write a
max(list)
that returns the element with the maximum value in the list (This is slightly trickier than it sounds.)
So the solution is what I came up to get it to work. I will talk about some mistakes that I made along the way and fix up the final solution.
Here is my solution:
def choose(a, _, true), do: a
def choose(_, b, false), do: b
def findMaxNumber([], value), do: value
def findMaxNumber([head|tail]), do: findMaxNumber(tail, head)
def findMaxNumber([head|tail], value ) do
findMaxNumber(tail, choose(head, value, head>value))
end
Let me try to explain.
When using findMaxNumber(list)
with the list = [0,1,5,2]
, we call the first function.
iex(1)> findMaxNumber(list)
Which then matches
def findMaxNumber([head|tail]), do: findMaxNumber(tail, head)
In Elixir, and many other languages, a List is simply two nodes, where head
is the first item in the list, while the tail is the rest of the items.
So when an array of [1,2,3,4,5]
is broken down, head = 1
while tail = [2,3,4,5]
def findMaxNumber(tail, head)
ends up calling
def findMaxNumber([head|tail], value)
which looks like the following:
def findMaxNumber([1|[5,2]], 0)
and calls findMaxNumber
recursively while passing in the function choose
. choose
would return the greater value of the two
values. It looks like this:
findMaxNumber([5,2], choose(1, 0, 1>0))
since 1>0
, the choose function def choose(a, _, true), do: a
will match, since it’s true.
then calls findMaxNumber
again with the new variables:
findMaxNumber([5|[2]], 1)
This time, head
will be greater than value
! so the recursive function
findMaxNumber([2], choose(5, 1, 5>1))
would make choose
return true.
the next iteration would look like this:
def findMaxNumber([2|[]], 5), do:
findMaxNumber([], choose(2, 5, 2>5))
choose(2, 5, 2>5))
would match the false choose function which is def choose(_, b, false), do: b
and 5 would remain the higher value.
Since the last function will be findMaxNumber([], value)
, it would just return the value!
That’s the solution. There’s an issue I need to get to.
Refactor Time
First, I noticed I can refactor the choose
functions.
def choose(a, _, true), do: a
def choose(_, b, false), do: b
can be
def choose(a, b) when a > b, do: a
def choose(a, b) when a <= b, do: b
I’ve been able to refactor the function this far…
def choose(a, b) when a > b, do: a
def choose(a, b) when a <= b, do: b
def findMaxNumber([head | tail]), do: findMaxNumber(tail, head)
def findMaxNumber([head|tail], value ) do
findMaxNumber(tail, choose(head, value))
end
def findMaxNumber([], value), do: value
Definitely fun stuff!