Parameterless nullsFirst and nullsLast and misc comparator combining functions.
This commit is contained in:
@@ -68,18 +68,23 @@ public inline fun <T> compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*>
|
||||
return compareValues(selector(a), selector(b))
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two values using the specified [selector] function to calculate the result of the comparison.
|
||||
* The function is applied to the given values [a] and [b] and return objects of type K which are then being
|
||||
* compared with the given [comparator].
|
||||
*/
|
||||
public inline fun <T, K> compareValuesBy(a: T, b: T, comparator: Comparator<K>, selector: (T) -> K): Int {
|
||||
return comparator.compare(selector(a), selector(b))
|
||||
}
|
||||
|
||||
// Not so useful without type inference for receiver of expression
|
||||
// compareValuesWith(v1, v2, compareBy { it.prop1 } thenByDescending { it.prop2 })
|
||||
/**
|
||||
* Compares two values using the specified [comparator].
|
||||
*/
|
||||
@suppress("NOTHING_TO_INLINE")
|
||||
public inline fun <T> compareValuesWith(a: T, b: T, comparator: Comparator<T>): Int = comparator.compare(a, b)
|
||||
|
||||
//// Not so useful without type inference for receiver of expression
|
||||
//// compareValuesWith(v1, v2, compareBy { it.prop1 } thenByDescending { it.prop2 })
|
||||
///**
|
||||
// * Compares two values using the specified [comparator].
|
||||
// */
|
||||
//@suppress("NOTHING_TO_INLINE")
|
||||
//public inline fun <T> compareValuesWith(a: T, b: T, comparator: Comparator<T>): Int = comparator.compare(a, b)
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
@@ -120,7 +125,11 @@ inline public fun <T> compareBy(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) co
|
||||
}
|
||||
}
|
||||
|
||||
public fun <T, K> compareBy(comparator: Comparator<K>, selector: (T) -> K): Comparator<T> {
|
||||
/**
|
||||
* Creates a comparator using the [selector] function to transform values being compared and then applying
|
||||
* the specified [comparator] to compare transformed values.
|
||||
*/
|
||||
inline public fun <T, K> compareBy(comparator: Comparator<K>, inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> K): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int = compareValuesBy(a, b, comparator, selector)
|
||||
}
|
||||
@@ -136,7 +145,19 @@ inline public fun <T> compareByDescending(inlineOptions(InlineOption.ONLY_LOCAL_
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparator using the primary comparator and
|
||||
* Creates a descending comparator using the [selector] function to transform values being compared and then applying
|
||||
* the specified [comparator] to compare transformed values.
|
||||
*
|
||||
* Note that an order of [comparator] is reversed by this wrapper.
|
||||
*/
|
||||
inline public fun <T, K> compareByDescending(comparator: Comparator<K>, inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> K): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int = compareValuesBy(b, a, comparator, selector)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparator comparing values after the primary comparator defined them equal. It uses
|
||||
* the function to transform value to a [Comparable] instance for comparison.
|
||||
*/
|
||||
inline public fun <T> Comparator<T>.thenBy(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) comparable: (T) -> Comparable<*>?): Comparator<T> {
|
||||
@@ -148,6 +169,19 @@ inline public fun <T> Comparator<T>.thenBy(inlineOptions(InlineOption.ONLY_LOCAL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a comparator comparing values after the primary comparator defined them equal. It uses
|
||||
* the [selector] function to transform values and then compares them with the given [comparator].
|
||||
*/
|
||||
inline public fun <T, K> Comparator<T>.thenBy(comparator: Comparator<K>, inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> K): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int {
|
||||
val previousCompare = this@thenBy.compare(a, b)
|
||||
return if (previousCompare != 0) previousCompare else compareValuesBy(a, b, comparator, selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a descending comparator using the primary comparator and
|
||||
* the function to transform value to a [Comparable] instance for comparison.
|
||||
@@ -161,6 +195,20 @@ inline public fun <T> Comparator<T>.thenByDescending(inlineOptions(InlineOption.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a descending comparator comparing values after the primary comparator defined them equal. It uses
|
||||
* the [selector] function to transform values and then compares them with the given [comparator].
|
||||
*/
|
||||
inline public fun <T, K> Comparator<T>.thenByDescending(comparator: Comparator<K>, inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> K): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int {
|
||||
val previousCompare = this@thenByDescending.compare(a, b)
|
||||
return if (previousCompare != 0) previousCompare else compareValuesBy(b, a, comparator, selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a comparator using the function to calculate a result of comparison.
|
||||
*/
|
||||
@@ -182,10 +230,36 @@ inline public fun <T> Comparator<T>.thenComparator(inlineOptions(InlineOption.ON
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this comparator and the given [comparator] such that the latter is applied only
|
||||
* when the former considered values equal.
|
||||
*/
|
||||
public fun <T> Comparator<T>.then(comparator: Comparator<T>): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int {
|
||||
val previousCompare = this@then.compare(a, b)
|
||||
return if (previousCompare != 0) previousCompare else comparator.compare(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this comparator and the given [comparator] such that the latter is applied only
|
||||
* when the former considered values equal.
|
||||
*/
|
||||
public fun <T> Comparator<T>.thenDescending(comparator: Comparator<T>): Comparator<T> {
|
||||
return object : Comparator<T> {
|
||||
public override fun compare(a: T, b: T): Int {
|
||||
val previousCompare = this@thenDescending.compare(a, b)
|
||||
return if (previousCompare != 0) previousCompare else comparator.compare(b, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not so useful without type inference for receiver of expression
|
||||
/**
|
||||
* Extends the given [comparator] of non-nullable values to a comparator of nullable values
|
||||
* considering null value less than any other value.
|
||||
* considering `null` value less than any other value.
|
||||
*/
|
||||
public fun <T: Any> nullsFirst(comparator: Comparator<T>): Comparator<T?> {
|
||||
return object: Comparator<T?> {
|
||||
@@ -198,9 +272,24 @@ public fun <T: Any> nullsFirst(comparator: Comparator<T>): Comparator<T?> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a comparator of nullable [Comparable] values
|
||||
* considering `null` value less than any other value.
|
||||
*/
|
||||
public fun <T: Comparable<T>> nullsFirst(): Comparator<T?> {
|
||||
return object: Comparator<T?> {
|
||||
override fun compare(a: T?, b: T?): Int {
|
||||
if (a === b) return 0
|
||||
if (a == null) return -1
|
||||
if (b == null) return 1
|
||||
return a.compareTo(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the given [comparator] of non-nullable values to a comparator of nullable values
|
||||
* considering null value greater than any other value.
|
||||
* considering `null` value greater than any other value.
|
||||
*/
|
||||
public fun <T: Any> nullsLast(comparator: Comparator<T>): Comparator<T?> {
|
||||
return object: Comparator<T?> {
|
||||
@@ -211,4 +300,19 @@ public fun <T: Any> nullsLast(comparator: Comparator<T>): Comparator<T?> {
|
||||
return comparator.compare(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a comparator of nullable [Comparable] values
|
||||
* considering `null` value greater than any other value.
|
||||
*/
|
||||
public fun <T: Comparable<T>> nullsLast(): Comparator<T?> {
|
||||
return object: Comparator<T?> {
|
||||
override fun compare(a: T?, b: T?): Int {
|
||||
if (a === b) return 0
|
||||
if (a == null) return 1
|
||||
if (b == null) return -1
|
||||
return a.compareTo(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,20 @@ class OrderingTest {
|
||||
assertEquals(v1, items[1])
|
||||
}
|
||||
|
||||
Test fun combineComparators() {
|
||||
val byName = compareBy<Item> { it.name }
|
||||
val byRating = compareBy<Item> { it.rating }
|
||||
val v3 = Item(v1.name, v1.rating + 1)
|
||||
val v4 = Item(v2.name + "_", v2.rating)
|
||||
assertTrue( (byName then byRating).compare(v1, v2) > 0 )
|
||||
assertTrue( (byName then byRating).compare(v1, v3) < 0 )
|
||||
assertTrue( (byName thenDescending byRating).compare(v1, v3) > 0 )
|
||||
|
||||
assertTrue( (byRating then byName).compare(v1, v2) < 0 )
|
||||
assertTrue( (byRating then byName).compare(v4, v2) > 0 )
|
||||
assertTrue( (byRating thenDescending byName).compare(v4, v2) < 0 )
|
||||
}
|
||||
|
||||
Test fun sortByThenBy() {
|
||||
val comparator = compareBy<Item> { it.rating } thenBy { it.name }
|
||||
|
||||
|
||||
@@ -584,7 +584,7 @@ class CollectionTest {
|
||||
listOf("", "sort", "abc").let {
|
||||
assertEquals(listOf("", "abc", "sort"), it.sortedBy { it.nonEmptyLength() })
|
||||
assertEquals(listOf("sort", "abc", ""), it.sortedByDescending { it.nonEmptyLength() })
|
||||
assertEquals(listOf("abc", "sort", ""), it.sortedWith(compareBy(nullsLast(compareBy<Int> {it})) { it.nonEmptyLength()}))
|
||||
assertEquals(listOf("abc", "sort", ""), it.sortedWith(compareBy(nullsLast<Int>()) { it.nonEmptyLength()}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user