易惯用的方式来定义订货一个简单的案例类易惯用的方式来定义订货一个简单的案例类(Easy idioma

2019-05-12 17:19发布

我有简单的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)

Answer 1:

我个人最喜欢的方法是使用元组所提供的隐性订货的,因为它是清晰,简洁,正确的是:

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 ,因此提供了一个排序直接消除了大多数情况下的隐式转换。


Answer 2:

object A {
  implicit val ord = Ordering.by(unapply)
}

这具有自动更新每当改变的好处。 但是,A的字段需要被放置在由订货会使用顺序。



Answer 3:

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

  1. 对于一次性使用排序.sortBy方法中,如已@Shadowlands显示
  2. 用于分拣延伸情况下类有序性状,如@Keith所述的再利用。
  3. 定义自定义排序。 这个方案的好处是,你可以重复使用排序,并有多种方式,以相同的类的实例进行排序:

     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类,因为它是不容易的事情滚下,因为字段名称未先验(至少在没有宏魔法)知道,你不能比其他的方式访问案例类领域名称/使用的产品迭代器。



Answer 4:

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

case class Person(name : String, age : Int, email : String)

def sortPeople(people : List[Person]) = 
    people.sortBy(Person.unapply)


Answer 5:

该sortBy方法是这样做,如(排序上的一个典型方式tag字段):

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


Answer 6:

既然你使用的情况下类 ,你可以用有序像这样的扩展:

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


文章来源: Easy idiomatic way to define Ordering for a simple case class