Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign an order for TreeSet in Scala without repeating myself

I have this segment of Scala code which defines an ordering and applies it to a TreeSet. This part compiles fine.

val acctOrdering = new Ordering[Account] {
  def compare(acc1: Account, acc2: Account) {

    // code to compare based on various criteria

  }
}

private var accountSet = new TreeSet[Account]()(acctOrdering)

Elsewhere in the code, I want to get the first element in the set (and later on get subsequent ones if the first one doesn't produce what I want, although that usually won't be necessary), based on the order I previously specified. I thought the following would work, but it didn't compile:

val firstAccount = accountSet.min

The error is "could not find implicit value for parameter cmp: Ordering[Account]"

However, if I specify the ordering object again when asking for the minimum, it compiles:

val firstAccount = accountSet.min(acctOrdering)

I thought it would have automatically used the ordering I gave at construction time, and incrementally sorting as I added to the set, so I wouldn't have to specify the ordering again when calling min.

What am I doing wrong? Do I need to explicitly define an implicit function somewhere?

like image 759
Gigatron Avatar asked Mar 27 '11 21:03

Gigatron


1 Answers

What is happening is that you are assuming min depends on the ordering of the set, but it doesn't. Specifically, min and max are generic methods available on pretty much any collection, and they take an implicit Ordering parameter.

However, if you try firstKey and lastKey, which are SortedSet-specific methods, they'll work without having to pass any implicit.

Edit

One question you might have posed is to how do you make sure your Account type can be ordered by any method expecting an Ordering. You can do that by putting an implicit definition inside Account's object companion, like this:

object Account {
  implicit val ord = new Ordering[Account] {
    def compare(ac1: Account, acc2: Account): Int = {
      // code to compare based on various criteria
    }
  }
}

Once you do that, you won't need to pass the ordering explicitly.

like image 98
Daniel C. Sobral Avatar answered Sep 22 '22 17:09

Daniel C. Sobral