'Sorting by a partial order in Scala

Partially sorting collections in Scala asks how to sort by a PartialOrdering in Scala. Comments state that the author should not be partially sorting in the example given. I do need to sort by a partial ordering -- I have countries which may be enclaves of other countries, and this induces a partial ordering.

So: given a List[T], where T extends PartialOrdering[T], is there a sensible way of sorting according to the partial ordering?



Solution 1:[1]

I have written an appropriate sort myself. Cases like this always make me think I have missed a standard library function.

  def sortByPartialOrdering[T](ts: Array[T], lessThan: (T, T) => Boolean): ListBuffer[T] = {
    val len = ts.size
    val visited = Array.fill[Boolean](len)(false)
    val postOrder = ListBuffer.empty[Int]

    def visit(n: Int): Unit = {
      visited(n) = true
      for (i <- 0 until len)
        if (!visited(i) && lessThan(ts(i), ts(n)))
          visit(i)
      postOrder += n
    }

    for (i <- 0 until len)
      if (!visited(i))
        visit(i)

    assert(postOrder.size == len)

    postOrder map ts
  }

Comments/improvements would be welcome -- I don't write that much Scala.

Solution 2:[2]

I am not entirely sure I understand the problem. But perhaps this conversion from PartialOrdering to Ordering works:

def sortWithPartialSort[A : PartialOrdering](list: Seq[A]): Seq[A] = {
  list.sorted(
    Ordering.fromLessThan { case (x,y) =>
      implicitly[PartialOrdering[A]].lt(x, y)
    }
  )
}

Note that PartialOrdering.lt is defined as:

def lt(x: T, y: T): Boolean = lteq(x, y) && !equiv(x, y)
def equiv(x: T, y: T): Boolean = lteq(x,y) && lteq(y,x)

so if I understand this correctly, with just lteq you can define a full ordering.

Note also that Seq.sorted implements a stable sort so equal items are not re-ordered.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mohan
Solution 2 Erik van Oosten