P02 - Find the Penultimate Element of a List
Peter brings us this solution:
(defn penultimate [xs]
{:doc "P02 (*) Find the last but one element of a list."
:pre [(seq? xs)]}
(loop [ret (first xs) xs xs]
(if (next xs)
(recur (first xs) (next xs))
ret)))
I can not comment much, since I’m no Clojure developer. In particular I would like to know what recur
does? A generic macro to do recursion on a function? Seems interesting…
This is my solution in Scala:
def penultimate[T](list: List[T]): T =
list match {
case List(first, last) => first
case first :: second :: rest => penultimate(second :: rest)
case _ => error("Can not find penultimate of this list: " + list)
}
Using pattern matching, it does the following:
- if it matches a list consisting of only two elements (first and last) return the first one
- if it matches a list consisting of a least two elements and a rest, do recursion using the second and the rest
- in any other case the list has an unacceptable for, raise an error
Note the two matching styles for a list. The first one using the de-structuring of the List (unapply
behind the scenes) and the second using the “consing” of list-elements.
This implementation either returns the sought element, or it raises an error. It might be a cleaner, more idiomatic Scala implementation to return an Option[T]
instead. Let’s explore that possibility:
def penultimate[T](list: List[T]): Option[T] =
list match {
case List(first, last) => Some(first)
case first :: second :: rest => penultimate(second :: rest)
case _ => None
}
It can now be used like this:
penultimate(myList) map { element => /* do something with element */ }
Or, if one wants to handle the case where None
is found:
penultimate(myList) getOrElse { /* no penultimate found, deal with this */}
Or, to handle both cases:
penultimate(myList) map { element =>
/* do something with element */
} getOrElse {
/* no penultimate found, deal with this */
}