간단한 케이스 클래스에 대한 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
. Ordering
s에 대한 암시 적 s 의 존재는 Tuple
에서에서 튜플의 모든 요소 에 대해 암시 적 존재 TupleN[...]
를 Ordered[TupleN[...]]
제공하는 것으로 변환 할 수있게하는데 , 이는 no로 데이터 유형을 정렬하는 것이 의미가 없기 때문에 항상 그래야합니다 .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별로 정렬합니다. 다음과 같은 몇 가지 이점이 있습니다.
- 정렬은 단일 위치에서 표시되는 코드 아티팩트로 정의됩니다. 여러 필드에 대해 복잡한 정렬이있는 경우 유용합니다.
- 스칼라 라이브러리에 구현 된 대부분의 정렬 기능은의 인스턴스를 사용하여 작동
Ordering
하므로 정렬을 제공하면 대부분의 경우 암시 적 변환이 직접 제거됩니다.
object A {
implicit val ord = Ordering.by(unapply)
}
A가 변경 될 때마다 자동으로 업데이트된다는 이점이 있습니다. 그러나 A의 필드는 주문시 사용할 순서대로 배치되어야합니다.
요약하면 다음과 같은 세 가지 방법이 있습니다.
- 일회성 정렬의 경우 @Shadowlands가 보여준 것처럼 .sortBy 메서드를 사용하십시오.
- @Keith가 말했듯이 정렬을 재사용하기 위해 Ordered 특성으로 케이스 클래스를 확장하십시오.
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
'Programing' 카테고리의 다른 글
Theme.AppCompat.Light.DarkActionBar와 같은 appcompat-v7 툴바 스타일을 어떻게 지정합니까? (0) | 2020.08.15 |
---|---|
바이트 배열에서 이메일 첨부 파일을 추가하는 방법은 무엇입니까? (0) | 2020.08.14 |
msbuild를 C # 6으로 업그레이드하는 방법은 무엇입니까? (0) | 2020.08.14 |
JPA에서 복합 기본 키를 만들고 처리하는 방법 (0) | 2020.08.14 |
관찰 가능한 배열에서 항목을 조건부로 푸시하는 방법은 무엇입니까? (0) | 2020.08.14 |