Finding the maximum element of an array is a relatively easy problem. An imperative solution would be to choose the first element as the max and then go through the rest of the array and assign the current element to the max if the current element is larger than the current max. In the end, the max variable will contain the max value of the array.
But we are here to learn about Scala and functional programming so mutating a variable is not what we want to do. Also, we do not want to go through the array using a loop because a loop counter is also variable, in functional programming we usually implement loops or in general iterations using recursion.
So let's see how we would implement a function with the following signature for finding the max value of a given array (or List):
def maxValue(elements: List[Int]): Int = ???For implementing recursion we can define a nested function inside our maxValue function which takes 2 parameters, one int which is the current max value, and one list which is the rest of the list. So the signature of the nested function for the recursive call is like this:
def loop(max: Int, elements: List[Int]): Int = ???This function should have a base case that returns and some other cases to call itself.
def loop(max: Int, elements: List[Int]): Int = {
if (elements.isEmpty) max
else if (elements.head > max) loop(elements.head, elements.tail)
else loop(max, elements.tail)
}And the main function we only need to call this loop function with the initial list's head and tail. Meaning that initially, we consider that the first element of the list is the maximum value. We also assume the initial list is not empty, otherwise our function crashes!
So the complete function is like this:
def maxValue(elements: List[Int]): Int = {
def loop(max: Int, elements: List[Int]): Int = {
if (elements.isEmpty) max
else if (elements.head > max) loop(elements.head, elements.tail)
else loop(max, elements.tail)
}
loop(elements.head, elements.tail)
}There are 2 things that we can improve on this function:
- It can not take an empty list
- It only works with a list of Int
First improvement, empty list thingy
- Fix it in the method signature
- Fix it in the method body
def maxValue(elements: NonEmptyList[Int]): Int = ???def maxValue(elements: List[Int]): Either[Throwable, Int] = ??? def maxValue(elements: List[Int]): Either[Throwable, Int] = {
def loop(max: Int, elements: List[Int]): Int = {
if (elements.isEmpty) max
else if (elements.head > max) loop(elements.head, elements.tail)
else loop(max, elements.tail)
}
elements match {
case Nil => Left(IllegalArgumentException("the list is empty"))
case head :: tail => Right(loop(head, tail))
}
} def maxValue[A](elements: NonEmptyList[A])(implicit ordering: Ordering[A]): A = {
def loop(max: A, elements: List[A]): A = {
if (elements.isEmpty) max
else loop(ordering.max(max, elements.head), elements.tail)
}
loop(elements.head, elements.tail)
} def main(args: Array[String]): Unit = {
val l = NonEmptyList(51, List(22, 3, 9))
println(maxValue(l))
}
Comments
Post a Comment