Kotlin: Passing operator as a function parameter - kotlin

I've the following function in Kotlin
fun evaluate(first:Int?, second:Int?) {
var result = 0
if (v.equals('*')) {
result = (first ?: 0) * (second ?: 0)
} else if (v.equals('+')) {
result = (first ?: 0) + (second ?: 0)
} else if (v.equals('-')) {
result = (first ?: 0) - (second ?: 0)
} else if (v.equals('/')) {
result = (first ?: 0) / (second ?: 0)
}
return result
}
I want to change it in a way so that I can pass as a third parameter needed operator and evalute the expression. Something like
fun evaluate(first:Int?, second:Int?, op: () -> Unit):Int {
return (first ?: 0).op(second ?: 0)
}
How can I pass the operator as a function in this case? I checked the same kind of a question, but it is not clear how you can do that with operator.

Writing a higher order function using a function type as a parameter allows using both built-in operators and lambda expressions for the operation, so this would look like:
fun evaluate(first: Int?, second: Int?, op: (Int, Int) -> Int): Int {
return op(first ?: 0, second ?: 0)
}
Which can be called with built-in operators such as:
val r1 = evaluate(value1, value2, Int::times)
val r2 = evaluate(value1, value2, Int::plus)
val r3 = evaluate(value1, value2, Int::minus)
val r4 = evaluate(value1, value2, Int::div)
And with custom functions:
val r5 = evaluate(value1, value2) { a, b -> (a * a) + b }
Now you can also assign the operators to variables, such as you v:
val v: (Int, Int)->Int = Int::times // typing needed on left to avoid ambiguous alternatives
// and then later...
val r6 = evaluate(value1, value2, v)
Note that a function written for signature Int.(Int)->Int can be passed into a parameter expecting (Int, Int)->Int because the receiver this will be passed in as the first parameter.

Change () -> Unit into Int.(Int) -> Int. Then all the other code should work as you've written it there.
On the calling side it this is the first int, and the first parameter is the second int: { other -> this * other }

you can try do that:
fun evaluate(first: Int?, second: Int? , v:String ): Int = v.op(first ?: 0, second ?: 0)
fun String.op(first:Int,second:Int):Int = when (this) {
"*" -> first * second
"+" -> first + second
//....
else -> throw Exception()
}
fun main(args: Array<String>) {
println(evaluate(2,3,"*"))
println(evaluate(2,3,"+"))
}

Related

Kotlin - Unexpected tokens (use ';' to separate expressions on the same line) with ternary operator in lambda function

I got an error Unexpected tokens error on the lambda function when I try to run this code:
fun main() {
val oddOrEven = { number: Int -> (number % 2 == 0) ? "Even" : "Odd" }
print(oddOrEven(2))
}
There's no ternary operator in Kotlin. See the discussion here.
if in Kotlin is an expression (so it can return a value) and you can do something like this:
fun main() {
val oddOrEven = { number: Int -> if(number % 2 == 0) "Even" else "Odd" }
println(oddOrEven(2))
}
There is a special operator:
val x = if (y == null) -1 else x
The above can be shortened to:
val x ?: -1
This is called the Elvis Operator - if the value is null it returns the other value (-1 in this case)

Is there a function to search in a ArrayList from a position?

I read carefully the ArrayList documentation in Kotlin and apparently there is no way to search a value in ArrayList starting from a pointer. The alternative is write your own function iterating the right elements in ArrayList and testing the condition.
So I've programmed the following code:
fun <T> ArrayList<T>.findNext(cond: (T) -> Boolean, p: Int = 0): Int {
for (i in p..this.lastIndex)
if (cond(this[i])) return i
return -1
}
data class Person (
var name: String,
var age: Int
)
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({it.name=="Paul"})) // 0
println(v.findNext({it.name=="Paul"}, 1)) // 2
println(v.findNext({it.name=="Paul"}, 3)) // -1
}
Is there something better than this?
You can avoid any intermediate collections:
inline fun <T> List<T>.findNext(p: Int = 0, cond: (T) -> Boolean) =
listIterator(p).withIndex().asSequence().find { cond(it.value) }?.let { it.index + p }
By swapping the arguments you can call it like this:
println(v.findNext {it.name=="Paul"}) // 0
println(v.findNext(1) {it.name=="Paul"}) // 2
println(v.findNext(3) {it.name=="Paul"}) // null
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({ it.name == "Paul" },0))//IndexedValue(index=0, value=Person(name=Paul, age=22))
println(v.findNext({ it.name == "Paul" },2))//IndexedValue(index=2, value=Person(name=Paul, age=50))
println(v.findNext({ it.name == "Paul" },3))//null
}
private fun <T> List<T>.findNext(cond: (T) -> Boolean, position: Int): IndexedValue<T>? {
return withIndex().filter { it.index >= position }.firstOrNull { cond(it.value) }
}
maybe use withIndex and a filter ?
val arrayNames = listOf<String>("Paul", "Ann", "Paul", "Roger","Peter")
arrayNames.withIndex().filter {
it.value == "Paul" //value contains the original name
}.forEach{
println(it.index) //indext contains the position.
}
this will give you the output 0 and 2
for your case (person object instead of String) you will use
it.value.name == "Paul"

Operator overloading Kotlin

I'm new to kotlin and I'm working on operators overloading for a custom class I defined. The class is called "Rational" and represents a rational number, like for example 117/1098. Class is defined as below and I have overloaded a bunch of operators, like plus, minus, times and so on. However I'm uncertain about what I have to do to overload "in" operator.
Here is my class:
data class Rational(val rational: String) {
private val numerator: BigInteger
private val denominator: BigInteger
init {
val splitted = rational.split("/")
numerator = splitted[0].toBigInteger()
denominator = when (splitted[1]) {
"0" -> throw Exception("not allowed")
else -> splitted[1].toBigInteger()
}
}
operator fun plus(number: Rational): Rational {
val gcm = denominator * number.denominator
val numerator = (gcm / denominator) * numerator + (gcm / number.denominator) * number.numerator
return Rational("$numerator/$gcm")
}
operator fun minus(number: Rational): Rational {
val gcm = denominator * number.denominator
val numerator = (gcm / denominator) * numerator - (gcm / number.denominator) * number.numerator
return Rational("$numerator/$gcm")
}
operator fun times(number: Rational): Rational {
val numerator = numerator * number.numerator
val denominator = denominator * number.denominator
return Rational("$numerator/$denominator")
}
operator fun div(number: Rational): Rational {
val numerator = numerator * number.denominator
val denominator = denominator * number.numerator
return Rational("$numerator/$denominator")
}
operator fun compareTo(number: Rational): Int {
val ratio = this.numerator.toFloat() / this.denominator.toFloat()
val numberRatio = number.numerator.toFloat() / number.denominator.toFloat()
if (ratio > numberRatio) {
return 1
} else if (ratio == numberRatio) {
return 0
}
return -1
}
operator fun unaryMinus(): Rational {
val inverseNumerator = -numerator
return Rational("$inverseNumerator/$denominator")
}
operator fun unaryPlus(): Rational {
return Rational("$numerator/$denominator")
}
operator fun rangeTo(end: Rational): Any {
var range: MutableList<Rational> = arrayListOf()
val startNumerator = this.numerator.toInt()
val endNumerator = end.numerator.toInt()
var index = 0
if (this.denominator == end.denominator) {
for (i in startNumerator..endNumerator) {
range.add(index, Rational("$i/$denominator"))
}
}
return range
}
operator fun contains(number: Rational): Boolean {
if (this.denominator % number.denominator == 0.toBigInteger()
&& this.numerator <= number.numerator) {
return true
}
return false
}
override fun toString(): String {
val gcd = numerator.gcd(denominator)
return if (gcd != null) {
val newNumerator = numerator / gcd
val newDenominator = denominator / gcd
"$newNumerator/$newDenominator"
} else {
"$numerator/$denominator"
}
}
}
infix fun Int.divBy(denominator: Int): Rational {
if (denominator == 0) {
throw Exception("denominator 0 not allowed")
}
return Rational("$this/$denominator")
}
infix fun Long.divBy(denominator: Long): Rational {
if (denominator == 0L) {
throw Exception("denominator 0 not allowed")
}
return Rational("$this/$denominator")
}
infix fun BigInteger.divBy(denominator: BigInteger): Rational {
if (denominator == 0.toBigInteger()) {
throw Exception("denominator 0 not allowed")
}
return Rational("$this/$denominator")
}
fun String.toRational(): Rational {
return Rational(this)
}
And here is my main body that obviously still doesn't compile:
fun main() {
val half = 1 divBy 2
val third = 1 divBy 3
val twoThirds = 2 divBy 3
println(half in third..twoThirds) // this line does not compile beacause in operator is not defined for the class
}
I guess I have to override "rangeTo" operator but I'm uncertain about the operator prototype. I there somebody that can please help me to get to the right track?
The way to make in work is for the third..twoThirds call to return something that has a contains(Rational) method, which is what the in call translates to.
One way to do this is to return a ClosedRange<Rational> here, like so:
operator fun rangeTo(end: Rational): ClosedRange<Rational> {
return object : ClosedRange<Rational> {
override val endInclusive: Rational = end
override val start: Rational = this#Rational
}
}
This puts a type constraint on Rational, as a ClosedRange needs a Comparable implementation to be able to determine whether a value belongs in it. You can do this by implementing the Comparable interface, and then adding operator to your existing compareTo operator (plus it's a good practice to rename the parameter to match the interface):
data class Rational(val rational: String) : Comparable<Rational> {
...
override operator fun compareTo(other: Rational): Int {
val ratio = this.numerator.toFloat() / this.denominator.toFloat()
val numberRatio = other.numerator.toFloat() / other.denominator.toFloat()
if (ratio > numberRatio) {
return 1
} else if (ratio == numberRatio) {
return 0
}
return -1
}
}
You could also avoid the conversion to floats entirely by using this implementation instead, as suggested in the comment below by #gidds:
override operator fun compareTo(other: Rational): Int {
return (numerator * other.denominator - denominator * other.numerator).signum()
}
Also, your current contains implementation could probably be discarded, as you no longer need it, and it functions rather oddly.
To add something other than the direct answer here: as #Eugene Petrenko suggested in their answer, it would be practical to add a couple constructors other than the one that uses a String, for example one that takes two Ints, and one that takes two BigIntegerss.
The in operator is declared inverse. You need an extension function on the right side that takes the left side.
https://kotlinlang.org/docs/reference/operator-overloading.html#in
You miss an infix function divBy to allow turing Int into Rational, e.g.
infix fun Int.divBy(i: Int) = Rational("$this/$i")
Not the code like val half = 1 divBy 2 will work. Theoretically, it may make sense to add a constructor for Rational from Ints to avoid parsing.
There is an incorrect return type in rangeTo method in the Rational class, it should not be Any. It should be declared as
data class RationalRange(val left: Rational, val right: Rational) {
operator fun contains(r: Rational) = left <= r && r <= right
}
operator fun rangeTo(end: Rational): RationalRange(this, end)
Now the example with x in a..b should work.
UPD: added the RationalRange. I missed the point, sorry. You do not need contains function implemented for the Rational class at all.
The compareTo function of Rational is unlikely to use .toFloat() instead, you may implement that directly with integer numbers
A straightforward solution is to implement the Comparable Interface in your class.
data class Rational(val rational: String) : Comparable<Rational>
Then implement the compareTo() function, with your comparison logic.
override fun compareTo(other: Rational): Int {
//Normalize the numerators of each rational
val thisNumerator = this.numerator * other.denominator
val otherNumerator = other.numerator * this.denominator
//Then compare them
return when{
thisNumerator > otherNumerator -> 1
thisNumerator < otherNumerator -> -1
else -> 0
}
}
This will resolve the compile error without you needing to override the rangeTo() function with custom logic.

Component destructuring with fewer than expected components

Let's say I want to do the following:
val (k, v) = pair.split("=".toRegex(), 2)
This code is fine if I always get 2 components from the split - however, if the delimiter is not present in the string, this code throws an exception, because the second element in the array isn't present.
The answer is almost certainly "no", but is there some way to coerce destructure to assign null values to missing components?
When destructuring objects, Kotlin calls componentN() for that object. For arrays, component1() is equal to get(0), component2() is equal to get(1), and so on.
So if the index is out of bounds, it'll throw ArrayIndexOutOfBoundsException, instead of returning null.
But you can make your operator function like this:
operator fun <T> Array<out T>.component1(): T? = if (size > 0) get(0) else null
operator fun <T> Array<out T>.component2(): T? = if (size > 1) get(1) else null
so if I run
val (k, v) = arrayOf(1)
println(k)
println(v)
the output will be
1
null
See:
Destructuring Declarations
You could add your own extension to List that adds the required number of null values to the end:
val (k, v) = pair.split("=".toRegex(), 2).padWithNulls(limit = 2)
Implementation can be done a couple of ways, here's just one:
private inline fun <reified E> List<E>.padWithNulls(limit: Int): List<E?> {
if (this.size >= limit) {
return this
}
val result: MutableList<E?> = this.toMutableList()
result.addAll(arrayOfNulls(limit - this.size))
return result
}
Here's a simpler one as well:
private fun <E> List<E>.padWithNulls(limit: Int): List<E?> {
val result: MutableList<E?> = this.toMutableList()
while (result.size < limit) {
result.add(null)
}
return result
}
Or wrapping this functionality even further:
val (k, v) = pair.splitAndPadWithNulls("=".toRegex(), 2)
private fun String.splitAndPadWithNulls(regex: Regex, limit: Int): List<String?> {
return this.split(regex, limit).padWithNulls(limit)
}
Its working for me
val pair="your string"
if(pair.isNotEmpty()&&pair.contains("=")) {
val (k, v) = pair.split("=".toRegex(), 2)
println(k)
println(v)
}
It doesn't cover as many cases as other answers (also might not be as obvious what's happening) but you can always force there to be at least the correct number of values to destructure (extra values will be ignored). Using your example you can just add null to increase the size of the list returned by split:
val (k, v) = "foo=bar".split("=".toRegex(), 2) + null
> k=foo, v=bar
val (k, v) = "foo".split("=".toRegex(), 2) + null
> k=foo, v=null
Playground example https://pl.kotl.in/W7gGYyAjC

Kotlin equivalent for Optional::map in Java8

Do you know if there is a shortcut for:
if (x == null) null else f(x)
For Java Optional you can just do:
x.map(SomeClass::f)
Kotlin utilizes its own approach to the idea of Option, but there're map, filter, orElse equivalents:
val x: Int? = 7 // ofNullable()
val result = x
?.let(SomeClass.Companion::f) // map()
?.takeIf { it != 0 } // filter()
?: 42 // orElseGet()
I ended up writing a full comparison here:
You can use let in this case, like this:
fun f(x : Int) : Int{
return x+1
}
var x : Int? = 1
println(x?.let {f(it)} )
=> 2
x = null
println(x?.let {f(it)} )
=> null
and as #user2340612 mentioned, it is also the same to write:
println(x?.let(::f)
You can try with let (link to documentation):
x?.let(SomeClass::f)
Example
fun f(n: Int): Int {
return n+1
}
fun main(s: Array<String>) {
val n: Int? = null
val v: Int? = 3
println(n?.let(::f))
println(v?.let(::f))
}
This code prints:
null
4