small medium large xlarge

Dave_gnome_head_isolated_pragsmall
16 Jul 2013, 02:25
Dave Thomas (381 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))

end

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

</details>

Generic-user-small
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
end

  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!

Generic-user-small
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.

91794c7bbbe28cb7e4f624e827ba1f35_pragsmall
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
end
Avatar_pragsmall
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 ])
end
Generic-user-small
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.

Generic-user-small
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))
Generic-user-small
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.

Generic-user-small
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])
  end

  defp get_max(first, second) when first > second do
    first
  end
  defp get_max(_, second), do: second
end
Patrick_pragsmall
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))
end
Generic-user-small
21 Sep 2014, 02:38
lv cheng peng (4 posts)

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

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

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

Generic-user-small
25 Dec 2014, 00:02
Pierre Sugar (57 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])
end
Generic-user-small
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
Generic-user-small
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)
end
U0x0gcxz_pragsmall
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)
end
C2f77d9bcc71d1f9ddabd89a8ddf9615_pragsmall
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)
  end

  defp _max([], biggest) do
    biggest
  end

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

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

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

Generic-user-small
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])
  end
  def max([a,b | tail]) when b >= a do
    max([b | tail])
  end
end
Generic-user-small
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)

end
20160310-gunnar_pragsmall
25 Jul 2015, 06:45
Felipe Juarez Murillo (9 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
end

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]) 
		else 
			max([second | rest]) 
		end
	end
end

IO.inspect MyList.max [1,5,9, 10,4,2]  # Prints 10
4c5c2c297ed9f4664cfbe7733a011fb2_pragsmall
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])
  end
11010008_886028121441016_8781768823206677829_n_pragsmall
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))
Vaultboy01_pragsmall
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)
  end
  def mymax([head | tail], m) when head <= m do
    mymax(tail, m)
  end
end

IO.puts MyList.mymax([5, 2, 90, 22])  # => 90
Generic-user-small
18 Oct 2015, 19:08
Johannes Frey (1 post)

My version:

defmodule MyList do
  
  def max(list), do: _max(list, 0)

  defp _max([], value), do: value
  defp _max([head | tail], value) when head >= value do
    _max(tail, head)
  end
  defp _max([head | tail], value) when head < value do
    _max(tail, value)
  end
end
Generic-user-small
12 Nov 2015, 22:19
Don Gray (1 post)

I found Kernel.max() in the docs. My version should be tail recursive.

defmodule MyList do
  # max([]) is an input error. Do I need/how to throw error? 

  def max([x]), do: x
  def max([head | tail]), do: _max(tail, head) # Head element is default max

  defp _max([x], max), do: Kernel.max(max, x)
  defp _max([head | tail], max), do: _max(tail, Kernel.max(max, head))

end
Generic-user-small
18 Nov 2015, 06:28
Ricky Marcelin (2 posts)
defmodule MyList do
  def max(list) do
    _max(list, hd(list))
  end

  defp _max([], value), do: value

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

  defp _max([head | tail], value) do
    _max(tail, value)
  end

Generic-user-small
18 Nov 2015, 08:26
nguyen vinh linh (1 post)

My solution is much simpe, it handle the negative value and does not require any more parameter but the LIST only. Using by: MyList.max [123,4,5,6,555]


defmodule MyList do
  def max(alist), do: (
    mymax(alist, List.first(alist))
  )
  def mymax([], val), do: (
    val
  )
  def mymax([head | tail], val) when head > val, do: (
    mymax(tail, head)
  )
  def mymax([head | tail], val) when head <= val, do: (
    mymax(tail, val)
  )
end

Generic-user-small
19 Nov 2015, 01:11
germain delpy (4 posts)

The 2 first elements of the list are reduced by Kernel.max recursively until the list is composed of one single element which is the biggest.

  def mapmax([head | _tail]), do:  IO.puts("the max number is #{head}")

  def mapmax([head | [tailHead | tailTail]]) do
    mapmax([Kernel.max(head, tailHead) | tailTail])
  end
Generic-user-small
30 Nov 2015, 03:48
Clinton De Young (3 posts)

Here’s mine. Maybe not the best, but I wanted to try it without resorting to the Kernel module.

def max(list), do: _max(list, 0)
defp _max([], val), do: val
defp _max([ h | t ], val), do: _max(t, h > val && h || val)
Avatar_pragsmall
02 Dec 2015, 02:07
Jaroslaw Zabiello (6 posts)

Without additional helpers:

defmodule MyList do
  def max([], value \\ 0) do 
    value
  end
  def max([head|tail], value) when head > value do
    MyList.max tail, head
  end
  def max([head|tail], value) when head <= value do
    MyList.max tail, value
  end
end
defmodule MyList do
  def max([head|tail], value \\ 0) do
    cond do
      tail == []    -> value
      head > value  -> MyList.max(tail, head)
      head <= value -> MyList.max(tail, value)
    end
  end
end

The shortest version:

defmodule MyList do
  def max(list), do: List.last Enum.sort list
end
976310_10201335063559319_1050362366_o_pragsmall
06 Dec 2015, 02:40
Andrés Alejandro García Hurtado (4 posts)

My Solution

defmodule MyList do
  def max([h]), do: h
  def max([h | t]) when h > hd(t), do: max [h | List.delete_at(t, 0)]
  def max(l = [h | t]) when h <= hd(t), do: max List.delete_at(l, 0)
end
Generic-user-small
30 Dec 2015, 19:28
Sunny Mittal (5 posts)

My solution:

def my_max(list), do: _my_max(list, 0)

  defp _my_max([], cur_max), do: cur_max
  defp _my_max([ head | tail ], cur_max) when head <= cur_max do
    _my_max tail, cur_max
  end
  defp _my_max([ head | tail ], cur_max) when head > cur_max do
    _my_max tail, head
  end

I know Kernel.max exists, but so does Enum.max, so I couldn’t draw the line for what would constitute “cheating” and rolled my own.

Generic-user-small
16 Jan 2016, 02:41
Nico piderman (4 posts)

Looks like most people preferred to use guards, here’s a different way:


  def max([]), do: 0
  def max(list), do: _max(list, 0)
  defp _max([], max), do: max
  defp _max([ head | tail], max) do
    cond do
      head > max -> _max(tail, head)
      head < max -> _max(tail, max)
    end                                                                                                                                                                           
  end   
Axl_pragsmall
16 Jan 2016, 12:47
Axl Mattheus (4 posts)
def max([]), do: {:error, :undefined}
def max([head | tail]), do: _max(tail, head)
defp _max([], max), do: max
defp _max([head | tail], max) when head > max, do: _max(tail, head)
defp _max([_ | tail], max), do: _max(tail, max)

Only need to check if head > max.

Generic-user-small
17 Jan 2016, 17:17
Riley White (4 posts)

It seems like this is a variation on reduce that needs specialized initial conditions, so here’s what I came up with. (Btw, calling with an empty list doesn’t really make sense, so maybe just not matching the empty list, as some others have done, is better than returning nil?)

  def max([]), do: nil
  def max([head]), do: head
  def max([head|tail]), do: reduce(tail, head, &(Kernel.max(&1, &2)))
Img_2708_pragsmall
21 Jan 2016, 13:29
Hunter Stewart (2 posts)

I really wanted to see if I could do this without looking up docs - took me a while but it was worth figuring out how simple it really was even without the kernel function.

  def max([max_val]), do: max_val
  def max([ max_val | [ head | tail ]]) when max_val >= head, do: max([ max_val | tail])
  def max([ max_val | [ head | tail ]]) when max_val <= head, do: max([ head | tail])
Generic-user-small
29 Jan 2016, 16:37
Arthur Granowski (7 posts)
defmodule MyList do
  def max(list), do: _max(list, 0)
  
  #Private functions
  defp _max([], maxnum),            do: maxnum
  defp _max([head | tail], maxnum), do: _max(tail, max(maxnum, head))
end

#Calling the functions...
#Return the element with a maximum value in the list.
#Sum of an empty list, []: assign a 0.
IO.puts MyList.max []               #=> 0
IO.puts MyList.max [1, 2, 3, 1]    #=> 3

Please note: max(maxnum, head) is the Kernel.max() function. The arity of max(maxnum, head) is different from the local max() - so it still worked. Obviously for readability should have used Kernel.max() rather than just max().

Generic-user-small
29 Jan 2016, 16:34
Arthur Granowski (7 posts)
defmodule MyList do
  def max(list) do
    _max(list, 0)
  end

  #Private functions
  defp _max([], maxnum) do
    maxnum
  end

  defp _max([head | tail], maxnum) do
    _max(tail, _findmax(maxnum, head))
  end

  defp _findmax(maxnum, head) when  head > maxnum do
    head
  end

  defp _findmax(maxnum, head) do
    maxnum
  end
end

#Calling the functions...
#Return the element with a maximum value in the list.
#Sum of an empty list, []: assign a 0.
IO.puts MyList.max []              #=> 0
IO.puts MyList.max [1, 2, 3, 1]    #=> 3

This was a second solution with a locally defined _findmax() rather than an Elixir library Kernel.max().

Generic-user-small
15 Feb 2016, 16:52
Alex Deva (4 posts)

Here’s mine:

defmodule ListRec do

  def max([h|t]) do
    maxp(t, h)
  end

  defp maxp([], x), do: x

  defp maxp([h|t], cm) when h > cm,  do: maxp(t, h)

  defp maxp([h|t], cm) when h <= cm, do: maxp(t, cm)

end

cm stands for “current maximum”. I can’t figure out how to do it without it, and therefore without those two helper private functions.

Elixir1_pragsmall
07 Mar 2016, 15:38
Beibut Yerzhanov (9 posts)

that’s my solution, also works with negative numbers:

defmodule MyList do

  def max(list),   do: _max(list, 0)

  defp _max([], maxres),              do: maxres

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

     maxres = head

    _max(tail, maxres)

  end

  defp _max([ head | tail ], maxres) when head < maxres do

   _max(tail, maxres)
 
   end

end
Generic-user-small
11 Apr 2016, 18:14
Jared Rader (1 post)

I see when I read “write a max(list) function, that doesn’t necessarily mean that the first argument has to be list.

Anyway, here’s my solution:

defmodule MyList do
  def reduce([], value, _), do: value

  def reduce([head | tail], value, func) do
    reduce(tail, func.(head, value), func)
  end

  def max([]), do: nil

  def max([x]), do: x

  def max([head | tail]) do
    greater_than = fn
      (x, y) when x > y -> x
      (x, y) when y > x -> y
    end

    reduce(tail, head, greater_than)
  end
end
Mms_pragsmall
12 Apr 2016, 00:46
Matt Sylvestre (1 post)
def mmax([], curMax), do: curMax
def mmax([head|tail], curMax) when curMax >= head, do: mmax(tail,curMax)
def mmax([head|tail], curMax) when curMax < head, do: mmax(tail,head) 

Note that I used mmax to avoid a conflict with Erlang max (likely a better way to avoid such conflicts but I am new to this, still I think the code above is fairly clean and understandable).

Generic-user-small
18 Apr 2016, 15:53
Sebastian Stephan (1 post)

I wanted to reuse the reduce function

~~~
defmodule MyList do
  def max(list=[h|_]) do
    Enum.reduce(list, h, 
      fn 
        new,  prevMax when new > prevMax -> new
        _,    prevMax                    -> prevMax
      end
    )
  end
end

~~~
Fernando_hamasaki_de_amorim_20151119_pragsmall
08 May 2016, 03:35
Fernando Hamasaki de Amorim (5 posts)

Simple and direct: head is the max accumulator, using only one guard.

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]]), do: max([head | tail])
 end
Elefante_pragsmall
06 Jun 2016, 03:11
Fernando Campos (4 posts)

It must deal with negative numbers also

defmodule MyList do

  def max([]), do: []
  def max([head|tail]), do: _max(tail, head)
  defp _max([], value), do: value
  defp _max([head|tail], value) do
    if value < head, do: value = head 
    _max(tail, value)
  end
end

IO.puts MyList.max []                 # []
IO.puts MyList.max [3]                # 3
IO.puts MyList.max [10, 1, 3, 5]      # 10
IO.puts MyList.max [-10, 1, 3, -5]    # 3
IO.puts MyList.max [-10, -1, -3, -5]  # -1
Generic-user-small
27 Jul 2016, 21:08
Patrick K (1 post)
defmodule MyList do
    def max([head | [] ]) do
         head
    end
    def max([head | tail]) do
        new_list = [head | tail] -- [get_lower(head, tail)]
        max(new_list)
    end
    def get_lower(current, [head | tail]) do
        if current <= head do
            current
        else
           head 
        end
    end
Generic-user-small
29 Jul 2016, 12:22
Ron A Arts (1 post)

Without using stuff that wasn’t covered in the book yet:

defmodule MyList do
  def maxval(list), do: _maxval(list, 0)
  defp _maxval([], value), do: value
  defp _maxval([head | tail], value) when head > value do _maxval(tail, head) end
  defp _maxval([head | tail], value) when head <= value do _maxval(tail, value) end
end
Generic-user-small
20 Aug 2016, 15:28
Chintan Thakkar (7 posts)
defmodule MyList do
  def max(list \\ []), do: _max(list,0)
  defp _max([], maxval), do: maxval
  defp _max([head|tail], maxval) when head > maxval, do: _max(tail, head)
  defp _max([_head|tail], maxval), do: _max(tail, maxval)
end


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

Generic-user-small
26 Aug 2016, 22:45
Jeff Knox (1 post)

Like a lot of others I built my own, here’s my effort:

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)
Generic-user-small
11 Sep 2016, 11:27
Nabil Allam (1 post)

Hi, I don’t know why nobody used pattern matching to solve the problem. I ask my selfe, is it a bad code quality when you use pattern matching instead of using when as a condition query? My solution is:

  def max(list), do: _max(list)

  defp _max([]), do: []
  defp _max([head | tail]), do: _max(tail, head)
  defp _max([], value), do: value

  defp _max([head|tail], value), do: _max(tail, _larger(head > value, head, value))
  defp _larger(true, head, _), do: head
  defp _larger(false, _, value), do: value
You must be logged in to comment