diff --git a/libraries/stdlib/src/kotlin/util/Ordering.kt b/libraries/stdlib/src/kotlin/util/Ordering.kt index 7988a44cef9..0bc11681934 100644 --- a/libraries/stdlib/src/kotlin/util/Ordering.kt +++ b/libraries/stdlib/src/kotlin/util/Ordering.kt @@ -68,13 +68,19 @@ public inline fun compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*> return compareValues(selector(a), selector(b)) } +public inline fun compareValuesBy(a: T, b: T, comparator: Comparator, 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 compareValuesWith(a: T, b: T, comparator: Comparator): Int = comparator.compare(a, b) +/** + * Compares two values using the specified [comparator]. + */ +@suppress("NOTHING_TO_INLINE") +public inline fun compareValuesWith(a: T, b: T, comparator: Comparator): Int = comparator.compare(a, b) + + /** * Compares two nullable [Comparable] values. Null is considered less than any value. @@ -114,6 +120,12 @@ inline public fun compareBy(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) co } } +public fun compareBy(comparator: Comparator, selector: (T) -> K): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(a, b, comparator, selector) + } +} + /** * Creates a descending comparator using the function to transform value to a [Comparable] instance for comparison. */ @@ -172,31 +184,31 @@ inline public fun Comparator.thenComparator(inlineOptions(InlineOption.ON // Not so useful without type inference for receiver of expression /** - * Extends the given comparator of non-nullable values to a comparator of nullable values + * Extends the given [comparator] of non-nullable values to a comparator of nullable values * considering null value less than any other value. */ -public fun Comparator.nullsFirst(): Comparator { +public fun nullsFirst(comparator: Comparator): Comparator { return object: Comparator { override fun compare(a: T?, b: T?): Int { if (a === b) return 0 if (a == null) return -1 if (b == null) return 1 - return this@nullsFirst.compare(a, b) + return comparator.compare(a, b) } } } /** - * Extends the given comparator of non-nullable values to a comparator of nullable values + * Extends the given [comparator] of non-nullable values to a comparator of nullable values * considering null value greater than any other value. */ -public fun Comparator.nullsLast(): Comparator { +public fun nullsLast(comparator: Comparator): Comparator { return object: Comparator { override fun compare(a: T?, b: T?): Int { if (a === b) return 0 if (a == null) return 1 if (b == null) return -1 - return this@nullsLast.compare(a, b) + return comparator.compare(a, b) } } } \ No newline at end of file diff --git a/libraries/stdlib/test/OrderingTest.kt b/libraries/stdlib/test/OrderingTest.kt index fea64583c92..c0ad41c054a 100644 --- a/libraries/stdlib/test/OrderingTest.kt +++ b/libraries/stdlib/test/OrderingTest.kt @@ -39,7 +39,7 @@ class OrderingTest { val v2: Item? = null val diff = compareValuesBy(v1, v2) { it?.rating } assertTrue(diff > 0) - val diff2 = compareBy { it.rating }.thenBy { it.name }.nullsLast().compare(v1, v2) + val diff2 = nullsLast(compareBy { it.rating }.thenBy { it.name }).compare(v1, v2) assertTrue(diff2 < 0) } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index c5bfdf5ea58..bcb478f92f7 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -827,9 +827,9 @@ class ArraysTest { test fun sortedNullableBy() { fun String.nullIfEmpty() = if (isEmpty()) null else this arrayOf(null, "").let { - expect(listOf(null, "")) { it.sortedWith(compareBy { it }.nullsFirst()) } - expect(listOf("", null)) { it.sortedWith(compareByDescending { it }.nullsLast()) } - expect(listOf("", null)) { it.sortedWith(compareByDescending { it.nullIfEmpty() }.nullsLast() ) } + expect(listOf(null, "")) { it.sortedWith(nullsFirst(compareBy { it })) } + expect(listOf("", null)) { it.sortedWith(nullsLast(compareByDescending { it })) } + expect(listOf("", null)) { it.sortedWith(nullsLast(compareByDescending { it.nullIfEmpty() })) } } } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 70f08c6902d..8450bbebfcd 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -572,13 +572,19 @@ class CollectionTest { test fun sortedNullableBy() { fun String.nullIfEmpty() = if (isEmpty()) null else this - listOf(null, "").let { -// expect(listOf(null, "")) { it.sortedBy { it.orEmpty()}} -// expect(listOf("", null)) { it.sortedByDescending { it.orEmpty() }} -// expect(listOf("", null)) { it.sortedByDescending { it?.nullIfEmpty() }} - expect(listOf(null, "")) { it.sortedWith(compareBy { it }.nullsFirst()) } - expect(listOf("", null)) { it.sortedWith(compareByDescending { it }.nullsLast()) } - expect(listOf("", null)) { it.sortedWith(compareByDescending { it.nullIfEmpty() }.nullsLast() ) } + listOf(null, "", "a").let { + expect(listOf(null, "", "a")) { it.sortedWith(nullsFirst(compareBy { it })) } + expect(listOf("a", "", null)) { it.sortedWith(nullsLast(compareByDescending { it })) } + expect(listOf(null, "a", "")) { it.sortedWith(nullsFirst(compareByDescending { it.nullIfEmpty() })) } + } + } + + test fun sortedByNullable() { + fun String.nonEmptyLength() = if (isEmpty()) null else length() + 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 {it})) { it.nonEmptyLength()})) } }