diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index f611a3055e4..ad1ab99481d 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -239,6 +239,25 @@ public fun > Array.max() : T? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Array.maxBy(f: (T) -> R) : T? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -252,6 +271,25 @@ public fun > Array.min() : T? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Array.minBy(f: (T) -> R) : T? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_BooleanArrays.kt b/libraries/stdlib/src/generated/_BooleanArrays.kt index 6d05a7a54ec..8a11421436f 100644 --- a/libraries/stdlib/src/generated/_BooleanArrays.kt +++ b/libraries/stdlib/src/generated/_BooleanArrays.kt @@ -225,6 +225,44 @@ public inline fun > BooleanArray.mapTo(result: C, return result } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > BooleanArray.maxBy(f: (Boolean) -> R) : Boolean? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > BooleanArray.minBy(f: (Boolean) -> R) : Boolean? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_ByteArrays.kt b/libraries/stdlib/src/generated/_ByteArrays.kt index 3856938fc65..d7c9dc54e90 100644 --- a/libraries/stdlib/src/generated/_ByteArrays.kt +++ b/libraries/stdlib/src/generated/_ByteArrays.kt @@ -238,6 +238,25 @@ public fun ByteArray.max() : Byte? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > ByteArray.maxBy(f: (Byte) -> R) : Byte? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun ByteArray.min() : Byte? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > ByteArray.minBy(f: (Byte) -> R) : Byte? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_CharArrays.kt b/libraries/stdlib/src/generated/_CharArrays.kt index 469ab5ae38b..384a038f226 100644 --- a/libraries/stdlib/src/generated/_CharArrays.kt +++ b/libraries/stdlib/src/generated/_CharArrays.kt @@ -225,6 +225,44 @@ public inline fun > CharArray.mapTo(result: C, tra return result } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > CharArray.maxBy(f: (Char) -> R) : Char? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > CharArray.minBy(f: (Char) -> R) : Char? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_DoubleArrays.kt b/libraries/stdlib/src/generated/_DoubleArrays.kt index 552333eb2a5..88f604ea2fe 100644 --- a/libraries/stdlib/src/generated/_DoubleArrays.kt +++ b/libraries/stdlib/src/generated/_DoubleArrays.kt @@ -238,6 +238,25 @@ public fun DoubleArray.max() : Double? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > DoubleArray.maxBy(f: (Double) -> R) : Double? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun DoubleArray.min() : Double? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > DoubleArray.minBy(f: (Double) -> R) : Double? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_FloatArrays.kt b/libraries/stdlib/src/generated/_FloatArrays.kt index 51933131d01..6d95e06a063 100644 --- a/libraries/stdlib/src/generated/_FloatArrays.kt +++ b/libraries/stdlib/src/generated/_FloatArrays.kt @@ -238,6 +238,25 @@ public fun FloatArray.max() : Float? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > FloatArray.maxBy(f: (Float) -> R) : Float? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun FloatArray.min() : Float? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > FloatArray.minBy(f: (Float) -> R) : Float? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_IntArrays.kt b/libraries/stdlib/src/generated/_IntArrays.kt index d11746fcd8e..a659efcaf00 100644 --- a/libraries/stdlib/src/generated/_IntArrays.kt +++ b/libraries/stdlib/src/generated/_IntArrays.kt @@ -238,6 +238,25 @@ public fun IntArray.max() : Int? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > IntArray.maxBy(f: (Int) -> R) : Int? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun IntArray.min() : Int? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > IntArray.minBy(f: (Int) -> R) : Int? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_Iterables.kt b/libraries/stdlib/src/generated/_Iterables.kt index afb3bdf5b65..917b4433355 100644 --- a/libraries/stdlib/src/generated/_Iterables.kt +++ b/libraries/stdlib/src/generated/_Iterables.kt @@ -225,6 +225,26 @@ public fun > Iterable.max() : T? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Iterable.maxBy(f: (T) -> R) : T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + + var maxElem = iterator.next() + var maxValue = f(maxElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -238,6 +258,26 @@ public fun > Iterable.min() : T? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Iterable.minBy(f: (T) -> R) : T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + + var minElem = iterator.next() + var minValue = f(minElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_Iterators.kt b/libraries/stdlib/src/generated/_Iterators.kt index 2b1e518840c..6585a4588a1 100644 --- a/libraries/stdlib/src/generated/_Iterators.kt +++ b/libraries/stdlib/src/generated/_Iterators.kt @@ -225,6 +225,25 @@ public fun > Iterator.max() : T? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Iterator.maxBy(f: (T) -> R) : T? { + if (!hasNext()) return null + + var maxElem = next() + var maxValue = f(maxElem) + while (hasNext()) { + val e = next() + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -238,6 +257,25 @@ public fun > Iterator.min() : T? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun , T: Any> Iterator.minBy(f: (T) -> R) : T? { + if (!hasNext()) return null + + var minElem = next() + var minValue = f(minElem) + while (hasNext()) { + val e = next() + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_LongArrays.kt b/libraries/stdlib/src/generated/_LongArrays.kt index cf7852fb132..63249c5d7f9 100644 --- a/libraries/stdlib/src/generated/_LongArrays.kt +++ b/libraries/stdlib/src/generated/_LongArrays.kt @@ -238,6 +238,25 @@ public fun LongArray.max() : Long? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > LongArray.maxBy(f: (Long) -> R) : Long? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun LongArray.min() : Long? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > LongArray.minBy(f: (Long) -> R) : Long? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/src/generated/_ShortArrays.kt b/libraries/stdlib/src/generated/_ShortArrays.kt index 72bea8c5652..3008b69145e 100644 --- a/libraries/stdlib/src/generated/_ShortArrays.kt +++ b/libraries/stdlib/src/generated/_ShortArrays.kt @@ -238,6 +238,25 @@ public fun ShortArray.max() : Short? { return max } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > ShortArray.maxBy(f: (Short) -> R) : Short? { + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + /** * Returns the smallest element or null if there are no elements */ @@ -251,6 +270,25 @@ public fun ShortArray.min() : Short? { return min } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > ShortArray.minBy(f: (Short) -> R) : Short? { + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + /** * Partitions this collection into a pair of collections */ diff --git a/libraries/stdlib/test/ArraysJVMTest.kt b/libraries/stdlib/test/ArraysJVMTest.kt index 04e4bf0d949..1974c3ba626 100644 --- a/libraries/stdlib/test/ArraysJVMTest.kt +++ b/libraries/stdlib/test/ArraysJVMTest.kt @@ -105,6 +105,38 @@ class ArraysJVMTest { expect(3.0, { doubleArray(2.0, 3.0).max() }) } + test fun minBy() { + expect(null, { intArray().minBy { it } }) + expect(1, { intArray(1).minBy { it } }) + expect(3, { intArray(2, 3).minBy { -it } }) + expect(2000000000000, { longArray(3000000000000, 2000000000000).minBy { it + 1 } }) + expect(1, { byteArray(1, 3, 2).minBy { it * it } }) + expect(3, { shortArray(3, 2).minBy { "a" } }) + expect(2.0, { floatArray(3.0, 2.0).minBy { it.toString() } }) + expect(2.0, { doubleArray(2.0, 3.0).minBy { Math.sqrt(it) } }) + } + + test fun minIndex() { + val a = intArray(1, 7, 9, -42, 54, 93) + expect(3, { a.indices.minBy { a[it] } }) + } + + test fun maxBy() { + expect(null, { intArray().maxBy { it } }) + expect(1, { intArray(1).maxBy { it } }) + expect(2, { intArray(2, 3).maxBy { -it } }) + expect(3000000000000, { longArray(3000000000000, 2000000000000).maxBy { it + 1 } }) + expect(3, { byteArray(1, 3, 2).maxBy { it * it } }) + expect(3, { shortArray(3, 2).maxBy { "a" } }) + expect(3.0, { floatArray(3.0, 2.0).maxBy { it.toString() } }) + expect(3.0, { doubleArray(2.0, 3.0).maxBy { Math.sqrt(it) } }) + } + + test fun maxIndex() { + val a = intArray(1, 7, 9, 239, 54, 93) + expect(3, { a.indices.maxBy { a[it] } }) + } + test fun sum() { expect(0) { intArray().sum() } expect(14) { intArray(2, 3, 9).sum() } diff --git a/libraries/stdlib/test/ArraysTest.kt b/libraries/stdlib/test/ArraysTest.kt index 5f99cedb92b..7b6ebc6db20 100644 --- a/libraries/stdlib/test/ArraysTest.kt +++ b/libraries/stdlib/test/ArraysTest.kt @@ -119,6 +119,34 @@ class ArraysTest { expect("b", { array("a", "b").max() }) } + test fun minBy() { + expect(null, { array().minBy { it } }) + expect(1, { array(1).minBy { it } }) + expect(3, { array(2, 3).minBy { -it } }) + expect('a', { array('a', 'b').minBy { "x$it" } }) + expect("b", { array("b", "abc").minBy { it.length } }) + } + + test fun maxBy() { + expect(null, { array().maxBy { it } }) + expect(1, { array(1).maxBy { it } }) + expect(2, { array(2, 3).maxBy { -it } }) + expect('b', { array('a', 'b').maxBy { "x$it" } }) + expect("abc", { array("b", "abc").maxBy { it.length } }) + } + + test fun minByEvaluateOnce() { + var c = 0 + expect(1, { array(5, 4, 3, 2, 1).minBy { c++; it * it } }) + assertEquals(5, c) + } + + test fun maxByEvaluateOnce() { + var c = 0 + expect(5, { array(5, 4, 3, 2, 1).maxBy { c++; it * it } }) + assertEquals(5, c) + } + test fun sum() { expect(0) { array().sum() } expect(14) { array(2, 3, 9).sum() } diff --git a/libraries/stdlib/test/CollectionTest.kt b/libraries/stdlib/test/CollectionTest.kt index 69f41c5f2f6..12cd22a5778 100644 --- a/libraries/stdlib/test/CollectionTest.kt +++ b/libraries/stdlib/test/CollectionTest.kt @@ -436,6 +436,44 @@ class CollectionTest { expect(3, { listOf(2, 3).iterator().max() }) } + test fun minBy() { + expect(null, { listOf().minBy { it } }) + expect(1, { listOf(1).minBy { it } }) + expect(3, { listOf(2, 3).minBy { -it } }) + expect('a', { listOf('a', 'b').minBy { "x$it" } }) + expect("b", { listOf("b", "abc").minBy { it.length } }) + expect(null, { listOf().iterator().minBy { it } }) + expect(3, { listOf(2, 3).iterator().minBy { -it } }) + } + + test fun maxBy() { + expect(null, { listOf().maxBy { it } }) + expect(1, { listOf(1).maxBy { it } }) + expect(2, { listOf(2, 3).maxBy { -it } }) + expect('b', { listOf('a', 'b').maxBy { "x$it" } }) + expect("abc", { listOf("b", "abc").maxBy { it.length } }) + expect(null, { listOf().iterator().maxBy { it } }) + expect(2, { listOf(2, 3).iterator().maxBy { -it } }) + } + + test fun minByEvaluateOnce() { + var c = 0 + expect(1, { listOf(5, 4, 3, 2, 1).minBy { c++; it * it } }) + assertEquals(5, c) + c = 0 + expect(1, { listOf(5, 4, 3, 2, 1).iterator().minBy { c++; it * it } }) + assertEquals(5, c) + } + + test fun maxByEvaluateOnce() { + var c = 0 + expect(5, { listOf(5, 4, 3, 2, 1).maxBy { c++; it * it } }) + assertEquals(5, c) + c = 0 + expect(5, { listOf(5, 4, 3, 2, 1).iterator().maxBy { c++; it * it } }) + assertEquals(5, c) + } + test fun sum() { expect(0) { ArrayList().sum() } expect(14) { arrayListOf(2, 3, 9).sum() } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Iterables.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Iterables.kt index f786ecf7293..f41e3aff852 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Iterables.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Iterables.kt @@ -140,5 +140,93 @@ fun iterables(): ArrayList { } } + templates add f("minBy(f: (T) -> R)") { + doc = "Returns the first element yielding the smallest value of the given function or null if there are no elements" + typeParam("R: Comparable") + typeParam("T: Any") + returns("T?") + Iterables.body { + """ + val iterator = iterator() + if (!iterator.hasNext()) return null + + var minElem = iterator.next() + var minValue = f(minElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem + """ + } + listOf(Arrays, PrimitiveArrays).forEach { + it.body { + """ + if (size == 0) return null + + var minElem = this[0] + var minValue = f(minElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem + """ + } + } + } + + templates add f("maxBy(f: (T) -> R)") { + doc = "Returns the first element yielding the largest value of the given function or null if there are no elements" + typeParam("R: Comparable") + typeParam("T: Any") + returns("T?") + Iterables.body { + """ + val iterator = iterator() + if (!iterator.hasNext()) return null + + var maxElem = iterator.next() + var maxValue = f(maxElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem + """ + } + listOf(Arrays, PrimitiveArrays).forEach { + it.body { + """ + if (isEmpty()) return null + + var maxElem = this[0] + var maxValue = f(maxElem) + for (i in 1..lastIndex) { + val e = this[i] + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem + """ + } + } + } + return templates } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Iterators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Iterators.kt index c9ff19789df..c21ae1772cd 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Iterators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Iterators.kt @@ -122,5 +122,53 @@ fun iterators(): List { } } + templates add f("minBy(f: (T) -> R)") { + doc = "Returns the first element yielding the smallest value of the given function or null if there are no elements" + typeParam("R: Comparable") + typeParam("T: Any") + returns("T?") + body { + """ + if (!hasNext()) return null + + var minElem = next() + var minValue = f(minElem) + while (hasNext()) { + val e = next() + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem + """ + } + } + + templates add f("maxBy(f: (T) -> R)") { + doc = "Returns the first element yielding the largest value of the given function or null if there are no elements" + typeParam("R: Comparable") + typeParam("T: Any") + returns("T?") + body { + """ + if (!hasNext()) return null + + var maxElem = next() + var maxValue = f(maxElem) + while (hasNext()) { + val e = next() + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem + """ + } + } + return templates.sort() } \ No newline at end of file