Skip to content

Instantly share code, notes, and snippets.

@shengc
Created July 17, 2018 01:33
Show Gist options
  • Save shengc/c9078b9b76192ae1d7fa8ee3f85ec21c to your computer and use it in GitHub Desktop.
Save shengc/c9078b9b76192ae1d7fa8ee3f85ec21c to your computer and use it in GitHub Desktop.

this gist demonstrates idiomatic way to do sorting of various kinds through functional programming

import scala.math.Ordering
import scala.util.control.TailCalls._

trait Sort {
  def sort[O: Ordering](xs: List[O]): List[O]
  def safeSort[O: Ordering](xs: List[O]): List[O]
}

class InsertionSort extends Sort {
  def sort[O](ls: List[O])(implicit Ord: Ordering[O]): List[O] = {
    def insert(x: O, xs: List[O]): List[O] =
      xs match {
        case Nil => List(x)
        case y :: ys =>
          if (Ord.compare(x, y) < 0) x :: y :: ys
          else y :: insert(x, ys)
      }

    ls match {
      case Nil => Nil
      case x :: xs => insert(x, sort(xs))
    }
  }

  private def isort[O](ls: List[O])(implicit Ord: Ordering[O]): TailRec[List[O]] = {
    def insert(x: O, xs: List[O]): TailRec[List[O]] =
      xs match {
        case Nil => done(List(x))
        case y :: ys =>
          if (Ord.compare(x, y) < 0) done(x :: y :: ys)
          else insert(x, ys).map(y :: _)
      }

    ls match {
      case Nil => done(Nil)
      case x :: xs =>
        isort(xs).flatMap(insert(x, _))
    }
  }

  override def safeSort[O: Ordering](xs: List[O]): List[O] = isort(xs).result
}

class SelectionSort extends Sort {
  def sort[O](ls: List[O])(implicit Ord: Ordering[O]): List[O] = {
    def select(xs: List[O]): (O, List[O]) =
      xs match {
        case Nil => throw new RuntimeException("not possible")
        case x :: Nil => (x, Nil)
        case y :: ys =>
          val (z, zs) = select(ys)
          if (Ord.compare(y, z) < 0) (y, z :: zs)
          else (z, y :: zs)
      }

    ls match {
      case Nil => Nil
      case _ =>
        val (x, xs) = select(ls)
        x :: sort(xs)
    }
  }

  private def isort[O](ls: List[O])(implicit Ord: Ordering[O]): TailRec[List[O]] = {
    def select(xs: List[O]): TailRec[(O, List[O])] =
      xs match {
        case Nil => throw new RuntimeException("not possible")
        case x :: Nil => done((x, Nil))
        case y :: ys =>
          select(ys) map { case (z, zs) =>
            if (Ord.compare(y, z) < 0) (y, z :: zs)
            else (z, y :: zs)
          }
      }

    ls match {
      case Nil => done(Nil)
      case _ =>
        select(ls).flatMap { case (x, xs) =>
          isort(xs).map(x :: _)
        }
    }
  }

  override def safeSort[O: Ordering](xs: List[O]): List[O] = isort(xs).result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment