Provide minWith and maxWith to find maximum and minimum values according to the given comparator.

#KT-9002 Fixed
This commit is contained in:
Ilya Gorbunov
2015-11-30 19:57:42 +03:00
parent b5e637bed5
commit 055c71e8d0
11 changed files with 433 additions and 1 deletions
@@ -4,6 +4,7 @@ import java.lang.*
import java.util.*
public object Collections {
@Deprecated("Use collection.maxWith(comparator) instead.", ReplaceWith("col.maxWith(comp)"))
public fun <T> max(col: Collection<T>, comp: Comparator<in T>): T = java.util.max(col, comp)
@Deprecated("Use list.sort() instead.", ReplaceWith("list.sort()"))
@@ -34,7 +34,7 @@ public class StdLibTestToJSTest extends StdLibQUnitTestSupport {
"collections/ComparisonDSL.kt",
"../../../js/js.libraries/test/core/assertTypeEquals.kt",
"text/StringTest.kt",
// TODO review: somethings FAILED if run:
"OrderingTest.kt",
"collections/SequenceTest.kt",
"collections/IterableTests.kt",
"collections/ArraysTest.kt",
+234
View File
@@ -8725,6 +8725,123 @@ public inline fun <R : Comparable<R>> ShortArray.maxBy(selector: (Short) -> R):
return maxElem
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Array<out T>.maxWith(comparator: Comparator<in T>): T? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun BooleanArray.maxWith(comparator: Comparator<in Boolean>): Boolean? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun ByteArray.maxWith(comparator: Comparator<in Byte>): Byte? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun CharArray.maxWith(comparator: Comparator<in Char>): Char? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun DoubleArray.maxWith(comparator: Comparator<in Double>): Double? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun FloatArray.maxWith(comparator: Comparator<in Float>): Float? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun IntArray.maxWith(comparator: Comparator<in Int>): Int? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun LongArray.maxWith(comparator: Comparator<in Long>): Long? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun ShortArray.maxWith(comparator: Comparator<in Short>): Short? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the smallest element or `null` if there are no elements.
*/
@@ -8991,6 +9108,123 @@ public inline fun <R : Comparable<R>> ShortArray.minBy(selector: (Short) -> R):
return minElem
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Array<out T>.minWith(comparator: Comparator<in T>): T? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun BooleanArray.minWith(comparator: Comparator<in Boolean>): Boolean? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun ByteArray.minWith(comparator: Comparator<in Byte>): Byte? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun CharArray.minWith(comparator: Comparator<in Char>): Char? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun DoubleArray.minWith(comparator: Comparator<in Double>): Double? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun FloatArray.minWith(comparator: Comparator<in Float>): Float? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun IntArray.minWith(comparator: Comparator<in Int>): Int? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun LongArray.minWith(comparator: Comparator<in Long>): Long? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun ShortArray.minWith(comparator: Comparator<in Short>): Short? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns `true` if the array has no elements.
*/
@@ -1436,6 +1436,20 @@ public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R):
return maxElem
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Iterable<T>.maxWith(comparator: Comparator<in T>): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var max = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the smallest element or `null` if there are no elements.
*/
@@ -1469,6 +1483,20 @@ public inline fun <T, R : Comparable<R>> Iterable<T>.minBy(selector: (T) -> R):
return minElem
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Iterable<T>.minWith(comparator: Comparator<in T>): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var min = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns `true` if the collection has no elements.
*/
+14
View File
@@ -141,6 +141,13 @@ public inline fun <K, V, R : Comparable<R>> Map<K, V>.maxBy(selector: (Map.Entry
return entries.maxBy(selector)
}
/**
* Returns the first entry having the largest value according to the provided [comparator] or `null` if there are no entries.
*/
public fun <K, V> Map<K, V>.maxWith(comparator: Comparator<in Map.Entry<K, V>>): Map.Entry<K, V>? {
return entries.maxWith(comparator)
}
/**
* Returns the first entry yielding the smallest value of the given function or `null` if there are no entries.
*/
@@ -148,6 +155,13 @@ public inline fun <K, V, R : Comparable<R>> Map<K, V>.minBy(selector: (Map.Entry
return entries.minBy(selector)
}
/**
* Returns the first entry having the smallest value according to the provided [comparator] or `null` if there are no entries.
*/
public fun <K, V> Map<K, V>.minWith(comparator: Comparator<in Map.Entry<K, V>>): Map.Entry<K, V>? {
return entries.minWith(comparator)
}
/**
* Returns `true` if the map has no entries.
*/
@@ -837,6 +837,20 @@ public inline fun <T, R : Comparable<R>> Sequence<T>.maxBy(selector: (T) -> R):
return maxElem
}
/**
* Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Sequence<T>.maxWith(comparator: Comparator<in T>): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var max = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the smallest element or `null` if there are no elements.
*/
@@ -870,6 +884,20 @@ public inline fun <T, R : Comparable<R>> Sequence<T>.minBy(selector: (T) -> R):
return minElem
}
/**
* Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements.
*/
public fun <T> Sequence<T>.minWith(comparator: Comparator<in T>): T? {
val iterator = iterator()
if (!iterator.hasNext()) return null
var min = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns `true` if the sequence has no elements.
*/
@@ -1349,6 +1349,19 @@ public inline fun <R : Comparable<R>> String.maxBy(selector: (Char) -> R): Char?
return maxElem
}
/**
* Returns the first character having the largest value according to the provided [comparator] or `null` if there are no characters.
*/
public fun CharSequence.maxWith(comparator: Comparator<in Char>): Char? {
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
}
/**
* Returns the smallest character or `null` if there are no characters.
*/
@@ -1413,6 +1426,19 @@ public inline fun <R : Comparable<R>> String.minBy(selector: (Char) -> R): Char?
return minElem
}
/**
* Returns the first character having the smallest value according to the provided [comparator] or `null` if there are no characters.
*/
public fun CharSequence.minWith(comparator: Comparator<in Char>): Char? {
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
}
/**
* Returns `true` if the char sequence has no characters.
*/
+2
View File
@@ -10,6 +10,8 @@ data class Item(val name: String, val rating: Int) : Comparable<Item> {
}
}
val STRING_CASE_INSENSITIVE_ORDER: Comparator<String> = compareBy { it: String -> it.toUpperCase() }.thenBy { it.toLowerCase() }.thenBy { it }
class OrderingTest {
val v1 = Item("wine", 9)
val v2 = Item("beer", 10)
@@ -1,6 +1,7 @@
package test.collections
import test.collections.behaviors.listBehavior
import test.compare.STRING_CASE_INSENSITIVE_ORDER
import java.util.*
import kotlin.test.*
import org.junit.Test as test
@@ -146,6 +147,28 @@ class ArraysTest {
expect('b', { charArrayOf('a', 'b').max() })
}
@test fun minWith() {
assertEquals(null, arrayOf<Int>().minWith(naturalOrder()) )
assertEquals("a", arrayOf("a", "B").minWith(STRING_CASE_INSENSITIVE_ORDER))
}
@test fun minWithInPrimitiveArrays() {
expect(null, { intArrayOf().minWith(naturalOrder()) })
expect(1, { intArrayOf(1).minWith(naturalOrder()) })
expect(4, { intArrayOf(2, 3, 4).minWith(compareBy { it % 4 }) })
}
@test fun maxWith() {
assertEquals(null, arrayOf<Int>().maxWith(naturalOrder()) )
assertEquals("B", arrayOf("a", "B").maxWith(STRING_CASE_INSENSITIVE_ORDER))
}
@test fun maxWithInPrimitiveArrays() {
expect(null, { intArrayOf().maxWith(naturalOrder()) })
expect(1, { intArrayOf(1).maxWith(naturalOrder()) })
expect(-4, { intArrayOf(2, 3, -4).maxWith(compareBy { it*it }) })
}
@test fun minBy() {
expect(null, { arrayOf<Int>().minBy { it } })
expect(1, { arrayOf(1).minBy { it } })
@@ -4,6 +4,7 @@ import java.util.*
import kotlin.test.*
import org.junit.Test as test
import test.collections.behaviors.*
import test.compare.STRING_CASE_INSENSITIVE_ORDER
import java.io.Serializable
class CollectionTest {
@@ -496,6 +497,20 @@ class CollectionTest {
expect(3, { listOf(2, 3).asSequence().max() })
}
@test fun minWith() {
expect(null, { listOf<Int>().minWith(naturalOrder()) })
expect(1, { listOf(1).minWith(naturalOrder()) })
expect("a", { listOf("a", "B").minWith(STRING_CASE_INSENSITIVE_ORDER) })
expect("a", { listOf("a", "B").asSequence().minWith(STRING_CASE_INSENSITIVE_ORDER) })
}
@test fun maxWith() {
expect(null, { listOf<Int>().maxWith(naturalOrder()) })
expect(1, { listOf(1).maxWith(naturalOrder()) })
expect("B", { listOf("a", "B").maxWith(STRING_CASE_INSENSITIVE_ORDER) })
expect("B", { listOf("a", "B").asSequence().maxWith(STRING_CASE_INSENSITIVE_ORDER) })
}
@test fun minBy() {
expect(null, { listOf<Int>().minBy { it } })
expect(1, { listOf(1).minBy { it } })
@@ -222,6 +222,36 @@ fun aggregates(): List<GenericFunction> {
body(Maps) { "return entries.minBy(selector)" }
}
templates add f("minWith(comparator: Comparator<in T>)") {
doc { f -> "Returns the first ${f.element} having the smallest value according to the provided [comparator] or `null` if there are no ${f.element.pluralize()}." }
returns("T?")
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) return null
var min = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(min, e) > 0) min = e
}
return min
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives) {
"""
if (isEmpty()) return null
var min = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(min, e) > 0) min = e
}
return min
"""
}
body(Maps) { "return entries.minWith(comparator)" }
}
templates add f("max()") {
doc { f -> "Returns the largest ${f.element} or `null` if there are no ${f.element.pluralize()}." }
returns("T?")
@@ -301,6 +331,37 @@ fun aggregates(): List<GenericFunction> {
body(Maps) { "return entries.maxBy(selector)" }
}
templates add f("maxWith(comparator: Comparator<in T>)") {
doc { f -> "Returns the first ${f.element} having the largest value according to the provided [comparator] or `null` if there are no ${f.element.pluralize()}." }
returns("T?")
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) return null
var max = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare(max, e) < 0) max = e
}
return max
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives) {
"""
if (isEmpty()) return null
var max = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare(max, e) < 0) max = e
}
return max
"""
}
body(Maps) { "return entries.maxWith(comparator)" }
}
templates add f("fold(initial: R, operation: (R, T) -> R)") {
inline(true)