small medium large xlarge

16 Jul 2013, 02:25
Dave Thomas (344 posts)
  • Write max(list) that returns the element with the maximum value in the list. (This is slightly trickier than it sounds.)

A Possible Solution</summary>

# Our solution uses the built-in max/2 function, which 
# returns the larger of its two numeric arguments.
# Although it isn't necessary, we call it as
# `Kernel.max` to avoid confusion

defmodule MyList do
  # max([]) is undefined...

  # max of a single element list is that element
  def max([x]), do: x

  # else recurse
  def max([ head | tail ]), do: Kernel.max(head, max(tail))


IO.puts MyList.max([4])       #=> 4
IO.puts MyList.max([5, 4, 3]) #=> 5
IO.puts MyList.max([4, 5, 3]) #=> 5
IO.puts MyList.max([3, 4, 5]) #=> 5


26 Jul 2013, 15:47
Scott Barron (3 posts)

I see that I have a long way to go to learning to do this stuff elegantly. Here is my initial solution, followed by three important things I learned comparing my code to Dave’s:

defmodule MyList do
  def max([head|tail]), do: _max(tail, head)
  defp _max([], greatest), do: greatest
  defp _max([head|tail], greatest), do: _max(tail, _max(head, greatest))
  defp _max(a, b) when a >= b, do: a
  defp _max(_a, b), do: b

  1. Kernel.max exists. I should have known better and looked that up rather than trying to roll my own into my function.

  2. I don’t always have to use [] as the place I break the recursion when processing lists. In this case [x] makes perfect sense and would eliminate some of the cruft in my answer.

  3. Probably most importantly, I started thinking at the head of the list and what to do with the rest rather than thinking about what things would look like with the recursion “unrolled”. Dave’s code pretty much looks at what would be the last element of the list, calls it the max, and rolls that up. Mine starts with the head, rolling it down, and keeping that messy greatest around for comparison.

This is great stuff, and I love these challenges over just looking at the “right” way of doing it and saying, “Yes, I understand that” without really learning how to arrive at that understanding. Thanks, Dave!

09 Aug 2013, 13:50
Victor Solis (1 post)

Scott, don’t feel bad about rolling your own function. You wouldn’t have learned how it worked, otherwise.

My first stab at this problem actually used Kernel.max. Then I did:

def max([]), do: 0
def max(list), do: Enum.sort(list) |> Enum.reverse |> hd

But I still tried to come up with a version without calling any built in functions because I kinda felt like I was cheating lol.

However, your implementation would result in an error if called with an empty list. It should be something like:

def max(list), do: _max(list, 0)
defp _max([], greatest), do: greatest
defp _max([ head | tail ], greatest) when head > greatest, do: _max(tail, head)
defp _max([ _head| tail ], greatest), do: _max(tail, greatest)

Apologies if you intended it to raise an error with an empty list though.

Dave, might I suggest that the solutions be actual implementations where possible instead of calling existing functions? I think it would help a great deal to see the proper implementations. Great book, btw.

22 Aug 2013, 08:25
Gabe Hollombe (2 posts)

@Scott, my solution was very similar to yours, except I used guard clauses. I agree that @Dave’s is easily better, but when I tackled this exercise my brain was in ‘use what you know’ not ‘look in the docs for help’ mode. =-)

defmodule MyList do
  def max([head|tail]), do: _max(tail, head)
  defp _max([head|tail], e) when head > e, do: _max(tail, head)
  defp _max([head|tail], e) when head <= e, do: _max(tail, e)
  defp _max([], e), do: e
25 Aug 2013, 23:08
Gavin James (1 post)

My solution maintained the maximum value as the head of the list, avoiding the need for an additional function parameter…

defmodule MyList do
  def max([ max ]), do: max
  def max([ max | [head|tail] ]) when max >= head, do: max([ max | tail ])
  def max([ max | [head|tail] ]) when max <  head, do: max([ head | tail ])
29 Sep 2013, 20:09
Daniel Ashton (7 posts)

Is there a Negative Infinity constant (or concept) in Elixir? With that, I think it could be written in terms of the reduce function that has already been defined, like this:

  def max(list), do: reduce(list, -10_000_000_000, _max(&1, &2))
  defp _max(x, y) when x > y, do: x
  defp _max(_, y), do: y

Just insert the negative infinity constant in place of the negative 10 billion above.

03 Nov 2013, 15:51
Daniel Ashton (7 posts)

It turns out you don’t need a negative infinity concept: just pass in the head value for the first comparison.

Here’s an alternate implementation:

def max(list), do: reduce(list, hd(list), &(&1 > &2 && &1 || &2))
01 Jun 2014, 05:33
Charles F. Munat (5 posts)
def max([head | []]), do: head  
def max([head | tail]), do: Kernel.max(head, max(tail))

Why would you avoid built-in functions? That’s what they’re for. The assignment is to get the max value from a list, not to rewrite the max function.

22 Jun 2014, 06:28
Rodrigo Salado Anaya (2 posts)

Very similar to the others solutions:

defmodule MyList do
  def max([]), do: {:error, "INPUT_ERROR"}
  def max([first]), do: first  
  def max(list) do
    [first | [second | tail]] = list
    max([get_max(first, second) | tail])

  defp get_max(first, second) when first > second do
  defp get_max(_, second), do: second
09 Jul 2014, 07:09
Patrick Oscity (13 posts)

Here is my version, using a guard clause instead of the builtin max function:

defmodule MyList do
  def max([x]), do: x
  def max([x, y]) when x > y, do: x
  def max([x, y]), do: y
  def max([head | tail]), do: max(head, max(tail))
21 Sep 2014, 02:38
lv cheng peng (4 posts)

defmodule Mylist do
  def max([head | []]) do

  def max([max_num | [head | tail]]) when max_num >= head do
    max([max_num | tail])

  def max([max_num | [head | tail]]) when max_num < head do
    max([head | tail])

25 Dec 2014, 00:02
Pierre Sugar (56 posts)
defmodule MyList do
  def max([]),                     do: []
  def max([max]),                  do: max
  def max([a,b|tail]) when a < b,  do: max([b | tail])
  def max([a,_b|tail]),            do: max([a | tail])
14 Mar 2015, 00:15
Larry Prall (1 post)

This is what I used. Not sure where it fits in the hierarchy:

def max([]), do: IO.puts("Undefined.")
def max([head|tail]) when tail != [], do: Kernel.max(head, max(tail))
def max([head|_tail]), do: head
25 Mar 2015, 03:24
Scott Smith (8 posts)

Used an accumulator, then had a hard time getting rid of it.

Lots of interesting solutions above.

defmodule MyList do
  # def max([]) is undefined
  def max([ head | tail ]), do: _max([head | tail], head)
  defp _max([], max_value), do: max_value
  defp _max([ head  | tail ], max_value) when head > max_value, do: _max(tail, head)
  defp _max([ _head | tail ], max_value)                      , do: _max(tail, max_value)
28 Mar 2015, 23:14
John Bohn (5 posts)

Rolled my own max as well. Used an accumulator to pull it off.

defmodule MyList do
  def max(list), do: _max(list, 0)
  def _max([], n), do: n
  def _max([head | tail], acc) when head >= acc, do: _max(tail, head)
  def _max([head | tail], acc) when head < acc, do: _max(tail, acc)
11 May 2015, 22:00
Clinton De Young (3 posts)

I rolled my own too using a ternary condition:

defmodule MyList do
  def getmax([]), do: nil
  def getmax([ head | tail ]), do: _getmax([ head | tail ], 0)
  defp _getmax([], max), do: max
  defp _getmax([ head | tail ], max), do: _getmax(tail, head > max && head || max)
16 May 2015, 13:22
Rebecca Skinner (6 posts)

Looks like I also have a ways to go about thinking “the functional way” :)

My first shot, I didn’t know about the inbuilt max/2 function, and also used an accumulator.

defmodule MyList do
  def max([head|tail]) do
    _max(tail, head)

  defp _max([], biggest) do

  defp _max([head|tail], biggest) when head > biggest do
    _max(tail, head)

  defp _max([_|tail], biggest) do
    _max(tail, biggest)

Also, my way doesn’t handle an empty list as input. Derp.

19 Jun 2015, 13:11
Johan De Klerk (1 post)
defmodule MyList do
  def max([a]), do: a
  def max([a,b | tail]) when a > b do
    max([a | tail])
  def max([a,b | tail]) when b >= a do
    max([b | tail])
20 Jul 2015, 21:45
Dragos Tudorache (2 posts)
defmodule ListAndRecursion do

  def list_max([], val), do: val

  def list_max([h | t], val) when h > val, do: list_max(t, h)

  def list_max([h | t], val) when h <= val, do: list_max(t, val)

25 Jul 2015, 06:45
Felipe Juarez Murillo (5 posts)

Based on Dragos Tudorache

defmodule MyList do
  def max(list), do: _max(list, 0)
  defp _max([head | tail], val) when head >  val, do: _max(tail, head)
  defp _max([head | tail], val) when head <= val, do: _max(tail, val)
  defp _max([], val), do: val

But this thing does not work well with negative numbers :( This only prove me that I need to learn a lot about functional programming and recursive things

Dsc_0232 - copy_pragsmall
01 Aug 2015, 16:21
Srikanth P Shreenivas (3 posts)

My solution

defmodule MyList do
	def max([]), do: nil
	def max([single | []]), do: single
	def max([first | [second | rest]]) do 
		if (first > second) do 
			max([first | rest]) 
			max([second | rest]) 

IO.inspect MyList.max [1,5,9, 10,4,2]  # Prints 10
11 Aug 2015, 06:49
Artem Medeusheyev (8 posts)

I supposed that Elixir must have max(a, b) function, but didn’t search for it and wrote without using it:

  defmodule ListFuncs do
    def max([f]), do: f
    def max([f, s | rest]) when f < s, do: max([s | rest])
    def max([f, _ | rest]), do: max([f | rest])
13 Aug 2015, 11:17
Tiago Davi (2 posts)

My Solution

 def max(list), do: _max(list, 0)	
 defp _max([], val), do: val
 defp _max([head | tail], val), do: _max(tail, (if head > val, do: head, else: val))
18 Sep 2015, 05:14
Markus Banfi (2 posts)
defmodule MyList do
  def mymax(list, m \\ 0)
  def mymax([], m), do: m
  def mymax([head | tail], m) when head > m do
    mymax(tail, head)
  def mymax([head | tail], m) when head <= m do
    mymax(tail, m)

IO.puts MyList.mymax([5, 2, 90, 22])  # => 90
  You must be logged in to comment