Although in Scala coding I prefer the functional programming style (through combinators or recursion) to the imperative style (through variables and iterations), THIS TIME is for this particular problem, the old school imperative nested loops lead to a simpler and more efficient code.
I donβt think that returning to the imperative style is a mistake for certain classes of problems, such as sorting algorithms, which usually convert the input buffer (more like a procedure), and not lead to a new sorted collection.
Here is my solution:
package bitspoke.algo import scala.math.Ordered import scala.collection.mutable.Buffer abstract class Sorter[T <% Ordered[T]] { // algorithm provided by subclasses def sort(buffer : Buffer[T]) : Unit // check if the buffer is sorted def sorted(buffer : Buffer[T]) = buffer.isEmpty || buffer.view.zip(buffer.tail).forall { t => t._2 > t._1 } // swap elements in buffer def swap(buffer : Buffer[T], i:Int, j:Int) { val temp = buffer(i) buffer(i) = buffer(j) buffer(j) = temp } } class InsertionSorter[T <% Ordered[T]] extends Sorter[T] { def sort(buffer : Buffer[T]) : Unit = { for { i <- 1 until buffer.length j <- i until 0 by -1 if (buffer(j) < buffer(j - 1)) } swap(buffer, j, j - 1) } }
As you can see, to achieve parametric polymorphism, instead of using java.lang.Comparable
I preferred scala.math.Ordered
and Scala View borders rather than upper bounds. This certainly works thanks to Scala Implicit Conversions of Primitive Types to Rich Wrappers.
You can write a client program as follows:
import bitspoke.algo._ import scala.collection.mutable._ val sorter = new InsertionSorter[Int] val buffer = ArrayBuffer(3, 0, 4, 2, 1) sorter.sort(buffer) assert(sorter.sorted(buffer))
source share