1

Below is an implementation of Selection sort written in Scala.

The line ss.sort(arr) causes this error : type mismatch; found : Array[String] required: Array[Ordered[Any]]

Since the type Ordered is inherited by StringOps should this type not be inferred ? How can I add the array of Strings to sort() method ?

Here is the complete code :

object SelectionSortTest {

  def main(args: Array[String]){

    val arr = Array("Hello","World")

    val ss = new SelectionSort()
    ss.sort(arr)
  }

}

class SelectionSort {

  def sort(a : Array[Ordered[Any]]) = {
    var N = a.length

    for (i <- 0 until N) {
        var min = i

        for(j <- i + 1 until N){
            if( less(a(j) , a(min))){
              min = j
            }
        exchange(a , i , min)
        }
    }

  }

  def less(v : Ordered[Any] , w : Ordered[Any]) = {
    v.compareTo(w) < 0
  }

  def exchange(a : Array[Ordered[Any]] , i : Integer , j : Integer) = {
    var swap : Ordered[Any] = a(i)
    a(i) = a(j)
    a(j) = swap
  }
}
blue-sky
  • 51,962
  • 152
  • 427
  • 752

3 Answers3

3

Array is invariant. You cannot use an Array[A] as an Array[B] even if A is subtype of B. See here why: Why are Arrays invariant, but Lists covariant?

Neither is Ordered, so your implementation of less will not work either.

You should make your implementation generic the following way:

object SelectionSortTest {

  def main(args: Array[String]){

    val arr = Array("Hello","World")

    val ss = new SelectionSort()
    ss.sort(arr)
  }

}

class SelectionSort {

  def sort[T <% Ordered[T]](a : Array[T]) = {
    var N = a.length

    for (i <- 0 until N) {
        var min = i

        for(j <- i + 1 until N){
            if(a(j) < a(min)){ // call less directly on Ordered[T]
              min = j
            }
        exchange(a , i , min)
        }
    }

  }

  def exchange[T](a : Array[T] , i : Integer , j : Integer) = {
    var swap = a(i)
    a(i) = a(j)
    a(j) = swap
  }
}

The somewhat bizarre statement T <% Ordered[T] means "any type T that can be implicitly converted to Ordered[T]". This ensures that you can still use the less-than operator.

See this for details: What are Scala context and view bounds?

Community
  • 1
  • 1
gzm0
  • 14,752
  • 1
  • 36
  • 64
  • the above code causes a compile time error at line ss.sort(arr) : "Multiple markers at this line - inferred type arguments [String] do not conform to method sort's type parameter bounds [T <: Ordered[T]] - inferred type arguments [String] do not conform to method sort's type parameter bounds [T <: Ordered[T]] - type mismatch; found : Array[String] required: Array[T]" I think I need to use Any instead of type T ? – blue-sky Apr 25 '13 at 21:57
  • No, you need to keep the `T` because `Array[T]` is invariant. An `Array[String]` is *NOT* an `Array[Any]`. What needs to be changed is `[T <: Ordered[T]]` to `[T <% Ordered[T]]`. This is a view bound: http://stackoverflow.com/questions/4465948/what-are-scala-context-and-view-bounds Required because `String` is not (Scala-)ordered since it is a Java type and not a Scala type, but can be converted to a (Scala-)ordered – gzm0 Apr 25 '13 at 22:01
  • ordering is not behaving as expected, if I add following code to end to end of sort method : " for(i <- 0 until N){ println("Ordered "+a(i)) }" and use ["e","b","C","d"] as the array the output is : Ordered b Ordered d Ordered c Ordered e when it should be Ordered b Ordered c Ordered d Ordered e – blue-sky Apr 25 '13 at 22:11
  • 1
    The fault is not with Ordered, but with Sort. exchange should be outside the `j` loop (one bracket lower). Note however that if you put an uppercase C in the input, it will be first in the result, as ordering is simply by ascii code, and all uppercases come before all lowercases. – Didier Dupont Apr 25 '13 at 23:19
1

The answer by @gzm0 (with some very nice links) suggests Ordered. I'm going to complement with an answer covering Ordering, which provides equivalent functionality without imposing on your classes as much.

Let's adjust the sort method to accept an array of type 'T' for which an Ordering implicit instance is defined.

def sort[T : Ordering](a: Array[T]) = {
  val ord = implicitly[Ordering[T]]
  import ord._ // now comparison operations such as '<' are available for 'T'
  // ...
  if (a(j) < a(min))
  // ...
}

The [T : Ordering] and implicitly[Ordering[T]] combo is equivalent to an implicit parameter of type Ordering[T]:

def sort[T](a: Array[T])(implicit ord: Ordering[T]) = {
  import ord._
  // ...
}

Why is this useful? Imagine you are provided with a case class Account(balance: Int) by some third party. You can now add an Ordering for it like so:

// somewhere in scope
implicit val accountOrdering = new Ordering[Account] {
  def compare(x: Account, y: Account) = x.balance - y.balance
}

// or, more simply
implicit val accountOrdering: Ordering[Account] = Ordering by (_.balance)

As long as that instance is in scope, you should be able to use sort(accounts).
If you want to use some different ordering, you can also provide it explicitly, like so: sort(accounts)(otherOrdering).

Note that this isn't very different from providing an implicit conversion to Ordering (at least not within the context of this question).

nadavwr
  • 1,820
  • 16
  • 20
0

Even though, when coding Scala, I'm used to prefer functional programming style (via combinators or recursion) over imperative style (via variables and iterations), THIS TIME, for this specific problem, old school imperative nested loops result in simpler and performant code.

I don't think falling back to imperative style is a mistake for certain classes of problems, such as sorting algorithms which usually transform the input buffer (more like a procedure) rather than resulting to a new sorted collection.

Here it 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 SelectionSorter[T <% Ordered[T]] extends Sorter[T] {
  def sort(buffer : Buffer[T]) : Unit = {
    for (i <- 0 until buffer.length) {
      var min = i
      for (j <- i until buffer.length) {
        if (buffer(j) < buffer(min))
          min = j
       }
       swap(buffer, i, min)
     }
  }
}

As you can see, to achieve parametric polymorphism, rather than using java.lang.Comparable, I preferred scala.math.Ordered and Scala View Bounds rather than Upper Bounds. That's 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 SelectionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)

assert(sorter.sorted(buffer))
pangiole
  • 981
  • 9
  • 10