by August 9, 2012
onIn order to get some more practice on programming in scala I started solving some problems of the probably well known 99 problems of other functional programming languages. I first found that kind of series on the haskell wiki that mentions the origin being the Ninety-Nine Prolog Problems.
This post now contains my solutions to the first 10 problems mentioned on the haskell wiki translated to scala. This first problems target the handling of lists being one of the most important data structure in functional programming.
class Problem001 extends Problem {
def number = 1
def getLast[T](input : List[T]) : T = {
input match {
case Nil => throw new IllegalArgumentException("empty list")
case head :: Nil => head
case _ :: tail => getLast(tail)
}
}
def test() = {
getLast(List(1, 2, 3, 4)) == 4
}
}
class Problem002 extends Problem {
def number = 2
def lastButOne[T](list : List[T]) : T = {
list match {
case Nil => throw new IllegalArgumentException("empty list")
case _ :: Nil => throw new IllegalArgumentException("list with one element only")
case last :: _ :: Nil => last
case _ :: tail => lastButOne(tail)
}
}
def test() = {
lastButOne(List(1,2,3,4)) == 3
}
}
class Problem003 extends Problem {
def number = 3
def getNth[T](list : List[T], n : Int) : T = {
list match {
case Nil => throw new IllegalArgumentException("index out of bounds")
case head :: tail if n == 1 => head
case _ :: tail => getNth(tail, n-1)
}
}
def test() = {
val lst = List(1,2,3,4,5)
getNth(lst, 3) == 3 &&
getNth(lst, 1) == 1 &&
getNth(lst, 5) == 5
}
}
The first element in the list is number 1.
class Problem004 extends Problem {
def number = 4
def numElements[T](list : List[T]) = {
def inner(lst : List[T], i : Int) : Int = {
lst match {
case Nil => i
case _ :: tail => inner(tail, i+1)
}
}
inner(list, 0)
}
def test() = {
val lst = List.range(0, 10)
numElements(lst) == 10 &&
numElements(List()) == 0
}
}
class Problem005 extends Problem {
def number = 5
def rev[T](list : List[T]) = {
def inner(lst : List[T], res : List[T]) : List[T] = {
lst match {
case Nil => res
case head :: tail => inner(tail, head :: res)
}
}
inner(list, List())
}
def test() = {
rev(List(1,2,3,4,5)) == List(5,4,3,2,1)
}
}
A palindrome can be read forward or backward (i.e. 12321
)
class Problem006 extends Problem {
def number = 6
def isPalindrome[T](list : List[T]) = {
list == list.reverse
}
def test() = {
isPalindrome(List(1,2,3,2,1)) &&
isPalindrome("madamimadam".toList) &&
!isPalindrome(List(1,3,1,2))
}
}
class Problem007 extends Problem {
def number = 7
def flattenList[T](list : List[List[T]]) = {
def inner(list : List[List[T]], res : List[T]) : List[T] = {
list match {
case Nil => res
case head :: tail =>
inner(tail, head.foldLeft(res)((l, h) => h :: l))
}
}
inner(list, List()) reverse
}
def test() = {
val lst = List(List(1,2), List(3), List(4,5,6))
flattenList(lst) == List(1,2,3,4,5,6)
}
}
class Problem008 extends Problem {
def number = 8
def compress[T](list : List[T]) = {
def inner(lst : List[T], last : T, res : List[T]) : List[T] = {
lst match {
case Nil => res
case head :: tail if head == last => inner(tail, last, res)
case head :: tail => inner(tail, head, head :: res)
}
}
list match {
case Nil => Nil
case head :: tail => inner(tail, head, List(head)) reverse
}
}
def test() = {
val lst = "aaabbbbbcccdefff".toList
compress(lst) == "abcdef".toList
}
}
If a list contains repeated elements they should be placed in separate sublists.
class Problem009 extends Problem {
def number = 9
def pack[T](list : List[T]) = {
def inner(lst : List[T], last : List[T], res : List[List[T]]) : List[List[T]] = {
lst match {
case Nil => last :: res
case hd :: tl if hd == last.head => inner(tl, hd :: last, res)
case hd :: tl => inner(tl, List(hd), last :: res)
}
}
list match {
case Nil => Nil
case head :: tail => inner(tail, List(head), List()) reverse
}
}
def test() = {
val lst = "aaaabbbcdeeee".toList
pack(lst) == List("aaaa".toList, "bbb".toList, List('c'), List('d'), "eeee".toList)
}
}
Use the result of problem 9 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as tuples (N E
) where N
is the number of duplicates of the element E
.
class Problem010 extends Problem {
def number = 10
def encode[T](list : List[T]) = {
def inner(lst : List[T], last : (Int, T), res : List[(Int, T)]) : List[(Int, T)] = {
val (count, elem) = last
lst match {
case Nil => last :: res
case hd :: tl if hd == elem => inner(tl, last.copy(_1 = count+1), res)
case hd :: tl => inner(tl, (1, hd), last :: res)
}
}
list match {
case Nil => Nil
case hd :: tl => inner(tl, (1, hd), List()) reverse
}
}
def test() = {
val lst = "aaabbcddeeeee".toList
encode(lst) == List((3, 'a'), (2, 'b'), (1, 'c'), (2, 'd'), (5, 'e'))
}
}