Programing

간단한 케이스 클래스에 대한 Ordering을 정의하는 쉬운 관용적 방법

lottogame 2020. 8. 14. 08:15
반응형

간단한 케이스 클래스에 대한 Ordering을 정의하는 쉬운 관용적 방법


간단한 스칼라 케이스 클래스 인스턴스 목록이 있고를 사용하여 예측 가능한 사전 순으로 인쇄하려고 list.sorted하지만 "...에 대해 정의 된 암시 적 순서 없음"을 수신합니다.

케이스 클래스에 대한 사전 순서를 제공하는 암시적인 것이 있습니까?

사전 식 순서를 케이스 클래스에 혼합하는 간단한 관용적 방법이 있습니까?

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. Orderings에 대한 암시 적 s 의 존재는 Tuple에서에서 튜플의 모든 요소 대해 암시 적 존재 TupleN[...]Ordered[TupleN[...]]제공하는 것으로 변환 할 수있게하는데 , 이는 no로 데이터 유형을 정렬하는 것이 의미가 없기 때문에 항상 그래야합니다 .Ordering[TN]T1, ..., TNOrdering

튜플에 대한 암시 적 순서는 복합 정렬 키와 관련된 모든 정렬 시나리오를위한 것입니다.

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별로 정렬합니다. 다음과 같은 몇 가지 이점이 있습니다.

  • 정렬은 단일 위치에서 표시되는 코드 아티팩트로 정의됩니다. 여러 필드에 대해 복잡한 정렬이있는 경우 유용합니다.
  • 스칼라 라이브러리에 구현 된 대부분의 정렬 기능은의 인스턴스를 사용하여 작동 Ordering하므로 정렬을 제공하면 대부분의 경우 암시 적 변환이 직접 제거됩니다.

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

A가 변경 될 때마다 자동으로 업데이트된다는 이점이 있습니다. 그러나 A의 필드는 주문시 사용할 순서대로 배치되어야합니다.


요약하면 다음과 같은 세 가지 방법이 있습니다.

  1. 일회성 정렬의 경우 @Shadowlands가 보여준 것처럼 .sortBy 메서드를 사용하십시오.
  2. @Keith가 말했듯이 정렬을 재사용하기 위해 Ordered 특성으로 케이스 클래스를 확장하십시오.
  3. Define a custom ordering. The benefit of this solution is that you can reuse orderings and have multiple ways to sort instances of the same class:

    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))
    

Answering your question Is there any standard function included into the Scala that can do magic like List((2,1),(1,2)).sorted

There is a set of predefined orderings, e.g. for String, tuples up to 9 arity and so on.

No such thing exists for case classes, since it is not easy thing to roll off, given that field names are not known a-priori (at least without macros magic) and you can't access case class fields in a way other than by name/using product iterator.


The unapply method of the companion object provides a conversion from your case class to an Option[Tuple], where the Tuple is the tuple corresponding to the first argument list of the case class. In other words:

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

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

The sortBy method would be one typical way of doing this, eg (sort on tag field):

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

Since you used a case class you could extend with Ordered like such:

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

참고URL : https://stackoverflow.com/questions/19345030/easy-idiomatic-way-to-define-ordering-for-a-simple-case-class

반응형