I am learning Kotlin and from the book, I have the fibonacci function, that demonstrates memoization concept:
import java.math.BigInteger
fun <T> List<T>.head(): T =
if (this.isEmpty())
throw IllegalArgumentException("head called on empty list")
else
this[0]
fun <T> List<T>.tail(): List<T> =
if (this.isEmpty())
throw IllegalArgumentException("tail called on empty list")
else
this.subList(1, this.size)
fun <T, U> foldLeft(list: List<T>, z: U, f: (U, T) -> U): U {
tailrec fun foldLeft(list: List<T>, acc: U, f: (U, T) -> U): U =
if (list.isEmpty())
acc
else
foldLeft(list.tail(), f(acc, list.head()), f)
return foldLeft(list, z, f)
}
fun fibo(number: Int): String {
tailrec fun fibo(
acc: List<BigInteger>, acc1: BigInteger,
acc2: BigInteger, x: BigInteger
): List<BigInteger> =
when (x) {
BigInteger.ZERO -> acc
BigInteger.ONE -> acc + (acc1 + acc2)
else -> fibo(
acc + (acc1 + acc2), acc2, acc1 + acc2,
x - BigInteger.ONE
)
}
val list = fibo(
listOf(),
BigInteger.ONE, BigInteger.ZERO, BigInteger.valueOf(number.toLong())
)
return makeString(list, ", ")
}
fun <T> makeString(list: List<T>, separator: String): String =
when {
list.isEmpty() -> ""
list.tail().isEmpty() -> list.head().toString()
else -> list.head().toString() +
foldLeft(list.tail(), "") { x, y -> x + separator + y }
}
fun main(args: Array<String>) {
println(fibo(5))
}
Could someone explain it to me, where is memoization here?
I... don't think there is any, actually.
What I wanted to write initially is that the acc parameter of the helper fibo function (the one with 4 parameters marked by tailrec) ends up containing the previous Fibonacci numbers, but it isn't actually accessed to retrieve them, so I don't think it counts.
Here is what I would consider memoization in this style (note: I made x an Int because it simplifies code and you won't calculate a Fibonacci number with index not fitting into a Long in sane time even with memoization):
fun fibo(x: Int): BigInteger {
tailrec fun fibo(
acc: List<BigInteger>, x: Int
): Pair<List<BigInteger>, BigInteger> =
when {
x < acc.size -> Pair(acc, acc[x])
x == acc.size -> {
val y = acc[x - 1] + acc[x - 2]
Pair(acc + y, y)
}
else ->
fibo(fibo(fibo(acc, x - 2).first, x - 1).first, x)
}
return fibo(listOf(BigInteger.ONE, BigInteger.ONE), x).second
}
You can simplify it a bit and make memoization (think a memo/note to remind you of something. Sort of like a cache.) a bit more explicit by doing something like this:
fun fib(n: Int, memo: MutableMap<Int, BigInteger> = mutableMapOf()): BigInteger {
if (memo.containsKey(n)) return memo[n]!!
if (n <= 2) return BigInteger.ONE
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]!!
}
You can see memoization in action here as each iteration stores the position and value of each number in the sequence. And within each fib call, we first check to see if the value already exists before creating another node in the call stack (think of each subsequent recursive call as creating a set of branching nodes until n is 1 or 2).
This is lightning fast, yielding linear O(n) time and space complexity even for cases like finding the 1000th number in the sequence. As opposed to O(2^n) without memoization.
First saw algorithm here and ported to kotlin: https://youtu.be/oBt53YbR9Kk
Related
What I thought didn't work
fun compute1(x: Double, y:Double) : Double {
return x + y
}
fun compute2(x: Number, y:Number) : Number {
return x + y // can't use plus
}
fun main() {
compute1(12, 13) // cant use integers
}
How to accomplish?
Solution should be as laconic as in java
public class MathEx {
public static double compute(double x, double y) {
return x+y;
}
}
You could overload the function to receive the combinations that you want
fun compute(x:Double, y:Double) = x + y
fun compute(x:Float, y:Float) = x + y
fun compute(x:Int, y:Int) = x + y
fun compute(x:Double, y:Int) = x + y
fun compute(x:Float, y:Int) = x + y
fun main() {
compute(12, 13)
}
Quite verbose, or you can define just one or two and convert the number before calling the function, which is not very efficient but it would work
fun compute(x:Double, y:Double) = x + y
fun main() {
compute(12.toDouble(), 13.toDouble())
}
from https://kotlinlang.org/docs/basic-types.html#floating-point-types
Note that unlike some other languages, there are no implicit widening conversions for numbers in Kotlin. For example, a function with a Double parameter can be called only on Double values, but not Float, Int, or other numeric values.
It's not a perfect solution since there are examples where you get rounding errors but for your use case this might be good enough
fun compute2(x: Number, y:Number) : Double{
return x.toDouble() + y.toDouble()
}
Suppose I have three functions foo, bar, baz, all of which return nullable types.
fun foo(): Int? = 1
fun bar(): Int? = 2
fun baz(): Int? = 3
I want to call them, and if all them returns non-null, I want to compute a value from their return values.
I could do this with statements, like this:
val x = foo()
val y = bar()
val z = baz()
val result = if (x != null && y != null && z != null) x + y + z else null
However, I don't like the fact that I have to declare 3 extra variables that I can still access afterwards. By having 3 extra statements like this, it also means that I cannot use expression-bodied functions, if I were writing a function that returns result.
If I use lets instead:
val result = foo()?.let { x ->
bar()?.let { y ->
baz()?.let { z ->
x + y + z
}
}
}
This creates a deep nesting. If it were only one function, this would have been fine, but with 3 functions or more, this makes my intention of "call these three functions, if they are all non null, add them together" rather unclear.
How can I write this in a way that clearly conveys my intention, but also making it a single expression?
If they are of different types, I think you need to write your own helper functions like these (different overloads needed for different numbers of parameters, because there's no other way for the compiler to know the types of the arguments):
inline fun <T : Any, U : Any, R> ifAllNotNull(t: T?, u: U?, block: (t: T, u: U) -> R): R? {
return when {
t != null && u != null -> block(t, u)
else -> null
}
}
inline fun <T : Any, U : Any, V : Any, R> ifAllNotNull(t: T?, u: U?, v: V?, block: (t: T, u: U, v: V) -> R): R? {
return when {
t != null && u != null && v != null -> block(t, u, v)
else -> null
}
}
val result = ifAllNotNull(foo(), bar(), baz()) { x, y, z -> x + y + z }
Note that all three parameters will be evaluated before any are checked for null.
Or if you want to do what you described (hiding the three variables after the result calculation) using just standard library functions, you can use run to limit the scope of the temporary variables:
val result = run {
val x = foo()
val y = bar()
val z = baz()
if (x != null && y != null && z != null) x + y + z else null
}
This would also give you the opportunity to short-circuit if you like:
val result = run {
val x = foo() ?: return#run null
val y = bar() ?: return#run null
val z = baz() ?: return#run null
x + y + z
}
You could filter out all null-values and only apply an operation on the list, if it did not shrink in size, e.g.:
fun sumIfNoneNull(values: List<Int?>): Int? = values
.filterNotNull()
.takeIf { it.size == values.size }
?.sum()
One may generalize this further, e.g.:
fun <T, R> List<T>.foldIfNoneNull(
initial: R,
operation: (acc: R, T) -> R
): R? = this
.filterNotNull()
.takeIf { nonNullList -> nonNullList.size == this.size }
?.fold(initial, operation)
You may use this like any other fold, e.g.:
listOf(foo(), bar(), baz()).foldIfNoneNull(0) { acc, cur -> acc + cur }
val result = listOf(foo(), bar(), baz())
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> acc + i
}
}
Or as function:
fun <T> apply(operation: (T, T) -> T, vararg values: T?): T? {
return values
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> operation(acc, i)
}
}
}
val result = apply({ x, y -> x + y }, foo(), bar(), baz())
I am really new in Kotlin programming language. I work with generic types and I found code statements shown below. What does it means? What is the meaning of each line?
class s(val b: t) : t by b {
fun f1(): Int = b.f3 + 1
override fun f2(g: Int): Any? = when {
g == 0 -> null
else -> b.f2(g - 1)
}
override fun l(g: Int, h: k?, z: m):
k = when {
g == 0 -> z.f1.f2.f3(1, z, true)
else -> b.l(g - 1, h, z)}}
override fun f4 (g: Int): Short = when {
g == 0 -> 0
else -> b.f4(g - 1)}}}
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
Looking for a way to get elementary functions and their derivatives I approach it like this:
abstract class Fun() {
/**
* i = 0 -- the function itself,
* i = 1, 2, 3, ... -- its successive derivatives
*/
abstract fun d(i: Int, x: Float): Float
}
class Lin(val k: Float) : Fun() {
// y = k*x
override fun d(i: Int, x: Float, p: Float) = when (i) {
0 -> k * x
1 -> k
else -> 0.0f
}
}
class Sum(val fun0: Fun, val fun1: Fun) : Fun() {
// y = fun0(x) + fun1(x)
override fun d(i: Int, x: Float, p: Float) = fun0.d(i, x) + fun1.d(i, x)
}
class Example(val fun1: Fun, val fun2: Fun){
var res = fun1.d(0, 5.25f) // fun1 value at 5.25f
res = fun1.d(1, 3.29f) // fun1 first derivative at 3.29f
val sum = Sum(fun1, fun2) // sum of f1 and f2
res = sum(0, 3.78f) // sum value at 3.78f
res = sum(1, 5.69f) // sum first derivative at 5.69f
}
Is there a more idiomatic way to do it in Kotlin?
I have exposed the problem as I had done in Java, that is, classes that contain functions. My question is if I can do the same with functions, pass them on to a class like:
class ParametricCurveXYZ(val fun_x: Fun, val fun_y: Fun, val fun_z: Fun) {
fun pointToXYZ(s: Float) = VectorXYZ(fun_x.d(0, s), fun_y.d(0, s), fun_z.d(0, s))
fun tangent(s: Float) = VectorXYZ(fun_x.d(1, s), fun_y.d(1, s), fun_z.d(1, s)).normalized()
}
You can use lambdas instead of regular classes and overload operators to combine lambdas.
fun lin(k: Float) = { i: Int, x: Float ->
when (i) {
0 -> k * x
1 -> k
else -> 0.0f
}
}
operator fun ((Int, Float) -> Float).plus(that: (Int, Float) -> Float) =
{ i: Int, x: Float -> this(i, x) + that(i, x) }
fun doSomething() {
val sum = lin(1f) + lin(2f)
val res = sum(0, 3.78f)
}