简单的惯用方法来定义一个简单的案例类的订购

我有一个简单的斯卡拉案例类实例的列表,我想打印他们在使用list.sorted可预测,字典顺序,但收到“没有隐式sorting定义…”。

是否存在一个隐含的提供案例类的词典sorting?

是否有简单的惯用方式将混合词典sorting整合到案例分类中?

 scala> case class A(tag:String, load:Int) scala> val l = List(A("words",50),A("article",2),A("lines",7)) scala> l.sorted.foreach(println) <console>:11: error: No implicit Ordering defined for A. l.sorted.foreach(println) ^ 

我不喜欢“黑客”:

 scala> l.map(_.toString).sorted.foreach(println) A(article,2) A(lines,7) A(words,50) 

我个人最喜欢的方法是利用为元组提供的隐式sorting,因为它是清楚,简洁和正确的:

 case class A(tag: String, load: Int) extends Ordered[A] { // Required as of Scala 2.11 for reasons unknown - the companion to Ordered // should already be in implicit scope import scala.math.Ordered.orderingToOrdered def compare(that: A): Int = (this.tag, this.load) compare (that.tag, that.load) } 

这是有效的,因为Ordered的伴侣定义了一个从Ordering[T]Ordered[T]的隐式转换,它在任何实现Ordered类的范围内。 对于Tuple的隐式Ordering的存在使得能够从TupleOrdered[TupleN[...]]提供对于元组的所有元素T1, ..., TN存在隐式Ordering[TN] ,应该总是这样,因为对没有sorting的数据types进行sorting是没有意义的。

元组的隐式sorting是任何涉及复合sorting键的sorting情况的前提:

 as.sortBy(a => (a.tag, a.load)) 

由于这个答案已经被certificate是stream行的,所以我想对其进行扩展,指出在某些情况下类似于以下的解决scheme可以被视为企业级™:

 case class Employee(id: Int, firstName: String, lastName: String) object Employee { // Note that because `Ordering[A]` is not contravariant, the declaration // must be type-parametrized in the event that you want the implicit // ordering to apply to subclasses of `Employee`. implicit def orderingByName[A <: Employee]: Ordering[A] = Ordering.by(e => (e.lastName, e.firstName)) val orderingById: Ordering[Employee] = Ordering.by(e => e.id) } 

给定es: SeqLike[Employee]es.sorted()将按名称sorting,而es.sorted(Employee.orderingById)将按IDsorting。 这有几个好处:

  • 这些sorting在一个位置被定义为可见的代码构件。 如果你在很多领域有复杂的sorting,这是非常有用的。
  • 在scala库中实现的大多数sortingfunction使用Ordering实例进行操作,因此在大多数情况下直接提供sorting可以直接消除隐式转换。
 object A { implicit val ord = Ordering.by(unapply) } 

这具有每当A改变时自动更新的好处。 但是,A的字段需要按顺序将使用它们的顺序放置。

总而言之,有三种方法可以做到这一点:

  1. 对于一次性sorting,使用.sortBy方法,正如@Shadowlands所示
  2. @Keith说,重新使用Ordered traitsorting扩展案例类。
  3. 定义一个自定义的顺序。 这个解决scheme的好处是你可以重用sorting,并有多种方法来sorting同一个类的实例:

     case class A(tag:String, load:Int) object A { val lexicographicalOrdering = Ordering.by { foo: A => foo.tag } val loadOrdering = Ordering.by { foo: A => foo.load } } implicit val ord = A.lexicographicalOrdering val l = List(A("words",1), A("article",2), A("lines",3)).sorted // List(A(article,2), A(lines,3), A(words,1)) // now in some other scope implicit val ord = A.loadOrdering val l = List(A("words",1), A("article",2), A("lines",3)).sorted // List(A(words,1), A(article,2), A(lines,3)) 

回答你的问题是否有任何标准函数包含在Scala中,可以像List((2,1),(1,2))那样执行魔术。

有一组预定义的顺序 ,例如对于String,最多9个元组的元组等等。

没有这样的事情存在的案例类,因为它是不容易的事情滚落,因为字段名称是不知道先验(至less没有macros魔术),你不能访问大小写字段的方式以外的方式名称/使用产品迭代器。

sortBy方法将是这样做的一个典型方法,例如(按tag字段sorting):

 scala> l.sortBy(_.tag)foreach(println) A(article,2) A(lines,7) A(words,50) 

既然你使用了一个case类,你可以像这样使用Ordered扩展:

 case class A(tag:String, load:Int) extends Ordered[A] { def compare( a:A ) = tag.compareTo(a.tag) } val ls = List( A("words",50), A("article",2), A("lines",7) ) ls.sorted 

伴随对象的unapply方法提供了从你的case类到一个Option[Tuple] ,其中Tuple是对应于case类的第一个参数列表的元组。 换一种说法:

 case class Person(name : String, age : Int, email : String) def sortPeople(people : List[Person]) = people.sortBy(Person.unapply)