Return the sum of a list of integers
Directions
Given a list of n integers, find the total sum using recursion. Do not use any functions from the Enum
module.
Examples
iex(1)> Lists.sum([1,2,3,4,5,6,7,8,9,10])
55
iex(2)> Lists.sum([0, 1, 2, 55, 98, 241])
397
iex(3)> Lists.sum([0])
0
iex(3)> Lists.sum([])
0
The object of this challenge is to combine pattern matching and recursion to form a working solution.
Constraints
- The input should be of type List.
- The length of the list may range from 0 to 15 integers.
- The return value must reflect the correct sum of the list.
- An empty list should return a value of 0.
Note
The recommended approach to solving coding challenges is to come up with a tentative solution using pseudo code. This will ensure you fully understand the question and you're heading in the right direction. Next, begin breaking the problem into smaller, more focused pieces. Smaller single-purposed functions are easier to reason about and ultimately solve. Once you've reached an acceptable solution, look for opportunities to refactor and improve your code.
Attempt to solve the problem by yourself. Spend approximately 10 minutes coming up with an original solution. There is nothing gained by copy /pasting someone else's solution or skipping straight to the answer. Create a new Elixir file and begin from a blank page. Start typing code, make comments about what you're trying to accomplish. Remember, try to break the problem down into smaller pieces and focus on solving one piece at a time. This is the best way to learn how to code. It's the best way to gain confidence in yourself and your abilities.
You may need to look up some documentation on how a particular function works and that's fine. Have the HexDocs open in a separate tab and refer to it as needed. Don't cheat yourself by copying someone else's solution. By completing the problem and learning organically your brain will make the necessary connections to transform short-term memory into long-term memory. Use the next section for help if you reach an impasse. Finally, or as a last resort, review the solution I've provided. Type it in manually and try to understand what each line of code is doing.
My approach
This is a relatively simple challenge to solve. It only requires a basic understanding of recursion and the List data type. A viable solution can be written using just two functions. The first function will be our "base case", the point at which our recursive function should stop. By reaching the base case, we've completed all of the necessary iterations. In this example, our base case is reached once we've added all of the integers in the list. At this point, we'll be left with an empty list. Therefore:
defmodule Lists do
@moduledoc """
Functions for working with Lists by recursion
"""
# define a base case, an empty list should return 0
def sum([]), do: 0
end
The sum/0
function is the first of two functions. Notice that if we keep the function on a single line we do not need to provide the closing "end" tag. The function above demonstrates the syntax for a single line function in Elixir, a "one-liner". The next function will be the crux of our solution. When we are passed a list we are going to use pattern matching to extract out the first element. Next, we'll add the first element to a recursive function call, passing in the remaining elements. Take a look:
defmodule Lists do
@moduledoc """
Functions for working with Lists by recursion
"""
# define a base case, an empty list should return 0
def sum([]), do: 0
# here is the main function that does the work
def sum([head | tail]) do
head + sum(tail)
end
end
The sum/1
function takes in a list of integers. The first integer (head) is pulled out. Then the function calls itself, passing in the remaining elements. Since our goal is to add up all of the elements, we add the "head" to an iterative call on the remaining elements. Let's look at an example:
iex> Lists.sum([1,2,3])
= 1 + sum([2,3])
== 1 + 2 + sum([3])
=== 1 + 2 + 3 + sum([])
#=> 6
Seeing the code written in its iterative form makes it quite clear what's happening. Each iteration extracts the head of the list and adds it to the head of the remaining list. This iteration continues until we reach an empty list, which is our base case. We can even add a guard clause to ensure that we are only working with integers. The complete solution is listed below.
defmodule Lists do
@moduledoc """
Functions for working with Lists by recursion
"""
# define a base case, an empty list should return 0
def sum([]), do: 0
# here is the main function that does the work
def sum([head | tail]) when is_integer(head) do
head + sum(tail)
end
end
The guard clause checks that the integer of each iteration is, in fact, an integer. If a string is passed in as an element the guard clause will provide us with a FunctionClauseError with a message that's clear and understandable:
Lists.sum([1,2,3,"t"])
** (FunctionClauseError) no function clause matching in Lists.sum/1
The following arguments were given to Lists.sum/1:
# 1
["t"]
I hope you found the "Sum of a List" challenge easy and even more, that you learned something from it. As section IV continues, expect the challenges to increase in difficulty but remain steadfast in your resolve to work through them independently. Nothing will be gained by copy/pasting or browsing over the answers. Take the time to work through the problems and reap the benefits of organic learning. You will thank me in the future, I can assure you.