0

I'm trying to implement a function called even/2 that takes a list of numbers and returns an equivalent list but one where all even numbers have been doubled. I'm supposed to use the function rem(n, k) which returns the reminder when dividing n with k.

I understand /2 means takes two arguments.

I tried to solve it by using an anonymous function to check the remainders of each element in the list if it's even, but I don't know how to place it in new list then output it.

Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
MRJ
  • 29
  • 8
  • i guess this is homework - and the teacher has asked for tail-recursion. Read up about it here: https://www.culttt.com/2016/06/06/understanding-recursion-tail-call-optimisation-elixir/ – GavinBrelstaff Feb 16 '19 at 17:30

5 Answers5

3

One can use rem/2 in guards:

Enum.map(input, fn
  even when rem(even, 2) == 0 -> even * 2
  odd -> odd
end)
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
1

UPDATE/REWRITE: Use this tail recursion

defmodule Main do 

  def doubleEven( [], output ) do # case of input empty list
    Enum.reverse output
  end

  def doubleEven( [head | tail], output ) do # any other length list
    if rem(head, 2) == 0 do 
      doubleEven(tail, [head*2 | output]) 
    else
      doubleEven(tail, [head | output]) 
    end
  end

end  

Which get called using:

Main.doubleEven( [1,2,3,4,5,6,7,8,9], [] )

and outputs

[1, 4, 3, 8, 5, 12, 7, 16, 9]
GavinBrelstaff
  • 3,016
  • 2
  • 21
  • 39
1

First, a simple way to do this with one argument:

defmodule Double do
  def double([]), do: []
  def double([head | tail]) when rem(head, 2) == 0, do: [head * 2 | double(tail)]
  def double([head | tail]), do: [head | double(tail)]
end

This uses pattern matching of the argument to assign the first element of the list to the head variable.

when rem(head, 2) == 0 is a guard that means this function clause will only get executed when it is true (the first item of the list is even, in this case).

We then return a new list consisting of the possibly doubled value, and use recursion to compute the rest of the list.

The above method builds up the result in the call stack. I suspect the reason you are asked to use two arguments is to take advantage of tail-call optimisation, which means even though a recursive call it made, no extra stack frames are used. Because we don't have a call stack in which to build the result, we add an extra output argument and build it there:

defmodule Double do
  def double([], output), do: Enum.reverse(output)
  def double([head | tail], output) when rem(head, 2) == 0, do: double(tail, [head * 2 | output])
  def double([head | tail], output), do: double(tail, [head | output])
end

Here we write a function that takes an input and an output list. The function calls itself until the input has been exhausted (is the empty list []), and builds up the answer in the output list, which it eventually returns. In each call, we prepend the current item to the output list.

iex> Double.double([1,2,3,4], [])
[1, 4, 3, 8]
Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
1

Here you go best implementation you can find :P

def double_even([]) do [] end
def double_even([h|t]) do
  case rem(h,2) do
    0 ->
      [h*2|double_even(t)]
    _ ->
      [h|double_even(t)]
  end
end
Z.Done
  • 36
  • 1
1
  def even([], acc), do: Enum.reverse(acc)
  def even([h|t], acc) when rem(h,2) == 0, do: even(t, [2*h|acc])
  def even([h|t], acc), do: even(t, [h|acc])
Marcus Gruneau
  • 787
  • 6
  • 6