I am not 100% sure what methods you think a collator should have.
But you have more flexibility if you define order in the case class:
val o = new Ordering[Name]{ def compare(a: Name, b: Name) = 3*math.signum(collator.compare(a.last,b.last)) + math.signum(collator.compare(a.first,b.first)) } names.sorted(o)
but you can also provide an implicit conversion from string ordering to name order:
def ostring2oname(os: Ordering[String]) = new Ordering[Name] { def compare(a: Name, b: Name) = 3*math.signum(os.compare(a.last,b.last)) + math.signum(os.compare(a.first,b.first)) }
and then you can use any order of strings to sort the names:
def oo = new Ordering[String] { def compare(x: String, y: String) = x.length compare y.length } val morenames = List("rat","fish","octopus") scala> morenames.sorted(oo) res1: List[java.lang.String] = List(rat, fish, octopus)
Edit: a convenient trick, if it wasn’t obvious, is that if you want to order N things and you are already using the comparison, you can simply multiply each thing by 3 ^ k (with the first, in order to multiply by the largest degree 3) and add.
If your comparisons are very time consuming, you can easily add a cascading comparison:
class CascadeCompare(i: Int) { def tiebreak(j: => Int) = if (i!=0) i else j } implicit def break_ties(i: Int) = new CascadeCompare(i)
and then
def ostring2oname(os: Ordering[String]) = new Ordering[Name] { def compare(a: Name, b: Name) = os.compare(a.last,b.last) tiebreak os.compare(a.first,b.first) }
(just be careful to x tiebreak ( y tiebreak ( z tiebreak w ) ) ) them x tiebreak ( y tiebreak ( z tiebreak w ) ) ) so that you do not perform implicit conversion several times in a row).
(If you really need quick comparisons, then you should write all this manually or pack the orders in an array and use a while loop. I assume that you are not so desperate for performance.)