a가 class Foo(val a: String, val b: Int, val c: Date)
있고 Foo
세 가지 속성을 모두 기반으로 s 목록을 정렬하고 싶습니다 . 어떻게해야합니까?
답변:
Kotlin의 stdlib는이를위한 여러 가지 유용한 도우미 메서드를 제공합니다.
먼저 compareBy()
메서드를 사용하여 비교기를 정의 하고 sortedWith()
확장 메서드에 전달 하여 목록의 정렬 된 복사본을받을 수 있습니다.
val list: List<Foo> = ...
val sortedList = list.sortedWith(compareBy({ it.a }, { it.b }, { it.c }))
둘째, 도우미 메서드를 사용하여 Foo
구현할 수 있습니다 .Comparable<Foo>
compareValuesBy()
class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {
override fun compareTo(other: Foo)
= compareValuesBy(this, other, { it.a }, { it.b }, { it.c })
}
그런 다음 sorted()
매개 변수없이 확장 메서드를 호출 하여 목록의 정렬 된 복사본을받을 수 있습니다.
val sortedList = list.sorted()
일부 값에서는 오름차순으로 정렬하고 다른 값에서는 내림차순으로 정렬해야하는 경우 stdlib에서 해당 기능도 제공합니다.
list.sortedWith(compareBy<Foo> { it.a }.thenByDescending { it.b }.thenBy { it.c })
의 vararg
버전은 compareValuesBy
바이트 코드에 인라인되지 않으므로 람다에 대해 익명 클래스가 생성됩니다. 그러나 람다 자체가 상태를 캡처하지 않으면 매번 람다를 인스턴스화하는 대신 싱글 톤 인스턴스가 사용됩니다.
의견에서 Paul Woitaschek이 언급했듯이 여러 선택자와 비교하면 매번 vararg 호출에 대한 배열이 인스턴스화됩니다. 모든 호출에서 복사되므로 배열을 추출하여이를 최적화 할 수 없습니다. 반면에 할 수있는 일은 로직을 정적 비교기 인스턴스로 추출하여 재사용하는 것입니다.
class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {
override fun compareTo(other: Foo) = comparator.compare(this, other)
companion object {
// using the method reference syntax as an alternative to lambdas
val comparator = compareBy(Foo::a, Foo::b, Foo::c)
}
}
ANEWARRAY kotlin/jvm/functions/Function1
compareBy
여러 람다가 있는 Kotlin 1.1.3부터는 모든 compareTo
호출 에 새 배열을 할당하지 않습니다 .
내림차순으로 정렬하려면 허용되는 답변을 사용할 수 있습니다.
list.sortedWith(compareByDescending<Foo> { it.a }.thenByDescending { it.b }.thenByDescending { it.c })
또는 다음과 같은 확장 기능을 만듭니다 compareBy
.
/**
* Similar to
* public fun <T> compareBy(vararg selectors: (T) -> Comparable<*>?): Comparator<T>
*
* but in descending order.
*/
public fun <T> compareByDescending(vararg selectors: (T) -> Comparable<*>?): Comparator<T> {
require(selectors.size > 0)
return Comparator { b, a -> compareValuesByImpl(a, b, selectors) }
}
private fun <T> compareValuesByImpl(a: T, b: T, selectors: Array<out (T) -> Comparable<*>?>): Int {
for (fn in selectors) {
val v1 = fn(a)
val v2 = fn(b)
val diff = compareValues(v1, v2)
if (diff != 0) return diff
}
return 0
}
사용 : list.sortedWith(compareByDescending ({ it.a }, { it.b }, { it.c }))
.
여러 필드를 기준으로 정렬하고 일부 필드는 내림차순으로, 다른 일부는 오름차순으로 정렬해야하는 경우 다음을 사용할 수 있습니다.
YOUR_MUTABLE_LIST.sortedWith(compareBy<YOUR_OBJECT> { it.PARAM_1}.thenByDescending { it.PARAM_2}.thenBy { it.PARAM_3})