我有简单的Scala case类实例的列表,我想打印出来的预见性,字典顺序使用list.sorted
,但收到“无隐性订货定义...”。
是否存在一个隐含的,对于case类提供了字典序?
有没有混合,在字典序成案例类简单的习惯的方法?
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)
我个人最喜欢的方法是使用元组所提供的隐性订货的,因为它是清晰,简洁,正确的是:
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
。 的隐式存在Ordering
S代表Tuple
S启用从转换TupleN[...]
到Ordered[TupleN[...]]
提供的隐式Ordering[TN]
存在对所有元素T1, ..., TN
的元组的,应该始终是因为它是没有意义的排序上没有一个数据类型的情况下Ordering
。
元组隐含的顺序是你去到涉及复合排序关键字排序的任何场景:
as.sortBy(a => (a.tag, a.load))
正如这个答案证明是受欢迎的,我想扩大它指出,解决类似以下可能在某些情况下被认为是企业级™:
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()
会按名称排序, es.sorted(Employee.orderingById)
将通过ID进行排序。 这有几个好处:
- 则排序是在一个单一的位置为可见代码工件限定。 如果你有很多领域各种复杂这是有用的。
- 在Scala库实现大多数排序功能操作使用的情况下
Ordering
,因此提供了一个排序直接消除了大多数情况下的隐式转换。
object A {
implicit val ord = Ordering.by(unapply)
}
这具有自动更新每当改变的好处。 但是,A的字段需要被放置在由订货会使用顺序。
总之,有三种方法可以做到这一点:
- 对于一次性使用排序.sortBy方法中,如已@Shadowlands显示
- 用于分拣延伸情况下类有序性状,如@Keith所述的再利用。
定义自定义排序。 这个方案的好处是,你可以重复使用排序,并有多种方式,以相同的类的实例进行排序:
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))
回答你的问题有没有纳入斯卡拉可以做到像魔法列表((2,1),(1,2))的任何标准功能。排序
有一组预定义的排序 ,例如,对于字符串,元组多达9元数等。
没有这样的事情存在case类,因为它是不容易的事情滚下,因为字段名称未先验(至少在没有宏魔法)知道,你不能比其他的方式访问案例类领域名称/使用的产品迭代器。
在unapply
伴随对象的方法提供了从你的情况类转化为Option[Tuple]
,其中, Tuple
是对应于壳体类的第一个参数列表中的元组。 换一种说法:
case class Person(name : String, age : Int, email : String)
def sortPeople(people : List[Person]) =
people.sortBy(Person.unapply)
该sortBy方法是这样做,如(排序上的一个典型方式tag
字段):
scala> l.sortBy(_.tag)foreach(println)
A(article,2)
A(lines,7)
A(words,50)
既然你使用的情况下类 ,你可以用有序像这样的扩展:
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