how to create kotlin infix function with 2 words? - unix

fun main(args: Array<String>) {
var arr = IntArray(10)
println(arr get size) // prints size of arr
arr print all //prints all elements of arr
I think "get size" is 2 infix function, get and size, and get function takes argument of size function result, and prints take argument of "all" function result, any solutions?

What you are trying to achieve doesn't make much sense and you shouldn't implement such things in production. Just for educational propose, something similar can be achieved:
infix fun <T> Array<T>.get(parameter: String): Int {
when(parameter) {
"size" -> return this.size
}
throw NotImplementedError()
}
and usage would be:
println(array get "size")
Edit:
The version where you would call array get size will look the following:
enum class GetType { size }
infix fun <T> Array<T>.get(parameter: GetType): Int {
when(parameter) {
GetType.size -> return this.size
}
However if you want to call size instead of GetType.size then you need to import everything in the enum class:
import GetType.*

Related

Correctly returning Int from Hashmap in a function

I have a function in Kotlin which takes in an Int argument and return a value based on a formula. To speed things up I store intermediate results in a HashMap<Int, Int>
private val calculatedResults = HashMap<Int, Int>()
private fun q2(n: Int): Int {
if(calculatedResults.containsKey(n)) {
return calculatedResults[n]
}
val q = ...
calculatedResults[n] = q
return q
}
I'm getting a type mismatch of Int found but Int? required at
return calculatedResults[n]
Im not sure how to correctly write this. I had
return calculatedResults[n]!!
But I'm not sure, if it's a bit hacky.
Should the return type of the function be Int? because while the HashMap might contain the key n the value could be null? Wouldn't that mean the HashMap should be <Int, Int?>?
getOrPut will check if a value exists for n. If the value exists, it will be returned. If the values does not exist the value returned by the lambda will be assigned and afterwards returned by getOrPut.
Take a look at this example:
fun calculate(n: Int) = n * 5 // some calculation
private fun q2(n: Int) = calculatedResults.getOrPut(n) {
calculate(n)
}
Should the return type of the function be Int? because while the
HashMap might contain the key n the value could be null? Wouldn't that
mean the HashMap should be ?
In this case the answer to the question is obviously "no" because if the value is missing you just add it. So, the value returned by q2 can never be null.
The underlying problem is that calculatedResults could have been modified by an other thread between contains (if(calculatedResults.containsKey(n))) and get (return calculatedResults[n]).
Even after checking with containsKey calculatedResults[n] could therefore possibly return a wrong result, including null, and this way of checking should be avoided.
Using !! should generally only be used when absolutely necessary, because it can cause a NPE. It definitely is hacky.
Use the following syntax to overcome the problem:
calculatedResults[n]?.let {
return it
}
Basically this is a nice way of saying
val result = calculatedResults[n]
if(result != null) {
return result
}
see https://kotlinlang.org/docs/reference/null-safety.html#safe-calls
Even better is to use the built-in getOrPut:
private fun q2(n: Int): Int {
return calculatedResults.getOrPut(n) { calcQ() }
}
private fun calcQ(): Int {
val q = ...
return q
}
Should the return type of the function be Int? because while the HashMap might contain the key n the value could be null? Wouldn't that mean the HashMap should be <Int, Int?>?
No, you did exactly the right thing when you defined the method signature. The compiler only complained because what happened within the method did not fit it. If you change the method signature you just move the problem to the function calling q2 without handling it.
You should consider re-writing this to more idiomatic code. It's a rather basic task to compute a value if it is not set in the map already:
fun q2(n: Int): Int {
return calculatedResults.getOrPut(n) {
42 //q
}
}

kotlin -- can I rewrite this map access to get rid of the ``!!``?

Let's say I have a
enum class ConceptualPosition{
A1,A2,A3,A4,A5,A6,A7,A8,
B1,B2,B3,B4,B5,B6,B7,B8,
C1,C2,C3,C4,C5,C6,C7,C8
}
And I now want to construct a Graph where every position has a Node.
import [...].domain.model.base.ConceptualPosition
import [...].domain.model.base.ConceptualPosition.*
import [...].domain.model.base.Node
import [...].domain.model.base.Node.MovableDirection.*
class MyGraph:Graph{
private val internalPositions = mutableMapOf<ConceptualPosition, Node>()
override val position by lazy {internalPositions.toMap().withDefault {
throw IllegalArgumentException("position '$it' does not exist")
}}
init{
//create nodes for all positions
ConceptualPosition.values().forEach { internalPositions[it] = Node(it) }
//now build graph
position[A1]!!.connectBothWaysWith(position[A2]!!,RIGHT)
position[A2]!!.connectBothWaysWith(position[A3]!!,RIGHT)
[...]
}
}
since I have a withDefault that immediately throws an exception and since Kotlin correctly infers the type of position to be Map<ConceptualPosition,Node>, I think I can be fairly sure that if a lookup does not fail, I get a non-null value out of it.
Kotlin apparently cannot safely infer that.
Can I refactor this (in a reasonable way) to get rid of the !!?
Use Map.getValue instead of get:
position.getValue(A1).connectBothWaysWith(position.getValue(A2),RIGHT)
Alternately, you could define your own version of withDefault with a more precise return type (the Kotlin standard library makes the equivalent private):
class MapWithDefault<K, V>(val map: Map<K, V>, val default: (K) -> V) : Map<K, V> by map {
override fun get(key: K): V = map[key] ?: default(key)
}
fun <K, V> Map<K, V>.withDefault(default: (K) -> V) = MapWithDefault(this, default)

Recursive anonymus function in kotlin

Im making this anonymus function, and i need it to call itself. Is there any way to do it? I tried the code below, which didnt work...
val example:Char = fun () : Char {
//Some code
if(condition) {
return this();
}
}
What should i replace 'this()' with?
Im pretty new to kotlin, so it would be really helpful with a response
You can't name anonymous functions (either with this syntax, or as a lambda) in Kotlin, and therefore you can't make them recursive either, because you have know way to reference themselves.
If you need recursion, you'll have to create a regular function, and call that:
fun helper() : Char {
if (condition) {
return helper();
}
...
}
val example = helper()
The good news is that you can basically create a regular, named function in any scope. They can be top level outside classes, class members, or just local functions nested within other functions. Wherever you can write down val example = ..., you can also create a function.
Calling an anonymous function sound complicated as there is no name to call it with :)
As I'm learning Kotlin myself at the moment, I tried something and came up with this, hope it helps:
import kotlin.test.Test
import kotlin.test.assertEquals
class StackOverflow51233329 {
#Test
fun test() {
var letter = 'A'
lateinit var example: () -> Char
example = {
letter++
if (letter >= 'C') letter else example()
}
assertEquals('C', example())
}
}
If you want to avoid using lateinit, you could use the Y combinator, which can be used to enable recursion when recursion is impossible directly. Declare this globally:
class RecursiveFunc<T, R>(val f: (RecursiveFunc<T, R>) -> (T) -> R)
fun <T, R> y(f: ((T) -> R) -> (T) -> R): (T) -> R {
val rec = RecursiveFunc<T, R> { r -> f { r.f(r)(it) } }
return rec.f(rec)
}
This code was taken from Rosetta Code. You use it like this:
val fac = y { f: ((Int) -> Int) ->
{ n: Int ->
if (n <= 1) 1 else n * f(n - 1)
}
}
println(fac(10))
f is the recursive function here, with a signature of (Int) -> Int. The rest of the function is pretty much the same as usual, but in lambda form. You can even use the usual function syntax if that's more familiar:
val fac = y { f: (Int) -> Int ->
fun(n: Int): Int {
return if (n <= 1) 1 else n * f(n - 1)
}
}

kotlin - Pass method reference to function

Let's say I have the following Java class:
public class A {
public Result method1(Object o) {...}
public Result method2(Object o) {...}
...
public Result methodN(Object o) {...}
}
Then, in my Kotlin code:
fun myFunction(...) {
val a: A = ...
val parameter = ...
val result = a.method1(parameter) // what if i want methodX?
do more things with result
}
and I want to be able to choose which methodX will be called inside myFunction. in Java, I would pass A::method7 as an argument and call it. in Kotlin it doesn't compile. How should I solve it in Kotlin?
You can also pass the method reference in Kotlin (without needing the heavy hammer that is reflection):
fun myFunction(method: A.(Any) -> Result) {
val a: A = ...
val parameter = ...
val result = a.method(parameter)
do more things with result
}
myFunction(A::method1)
myFunction {/* do something in the context of A */}
This declares method as part of A, meaning you can call it with normal object.method() notation. It Just Works™ with the method reference syntax.
There's also another form that works with the same call syntax, but makes A more explicit:
fun myFunction(method: (A, Any) -> Result) { ... }
myFunction(A::method1)
myFunction {a, param -> /* do something with the object and parameter */}
You can actually do this exactly like you wanted to:
fun myFunction(kFunction: KFunction2<A, #ParameterName(name = "any") Any, Result>) {
val parameter = "string"
val result: Result = kFunction(A(), parameter)
//...
}
myFunction(A::method1)
myFunction(A::method2)

Stackoverflow error on factorial using recursion on ktolin

This is my code
This gives stack overflow error 30 times on the output console
fun main(args:Array<String>){
var no:Int=Integer.parseInt(readLine())//read input from user and convert to Integer
var ans:Int=calculateFact(no) //call function and store to ans variable
println("Factorial of "+no+" is "+ans) //print result
}
fun calculateFact(no:Int):Int //function for recursion
{
if(no==0) {
return 1 }
return (no*calculateFact(no))
}
I don't know what is error
solve plz
You should return
no*calculateFact(no - 1)
not
no*calculateFact(no)
otherwise the recursion can never end.
Other than the mistake in the recursion that was already pointed out, it's worth mentioning that your method will still only work correctly for numbers up to 12, since 13! is larger than the maximum value that you can store in an Int. Therefore, for numbers 13 and up, you'll essentially get "random" results due to overflow.
If you just use BigInteger instead, it will work until the call stack gets too deep and causes a stack overflow, this happens around 8000 on my machine.
fun calculateFact(no: BigInteger): BigInteger {
if (no == BigInteger.ZERO) {
return BigInteger.ONE
}
return (no * calculateFact(no - BigInteger.ONE))
}
fun main(args: Array<String>) {
val no: BigInteger = BigInteger(readLine())
val ans: BigInteger = calculateFact(no)
println("Factorial of $no is $ans")
}
If you want to handle numbers larger than that, you can use a tailrec function (this specific solution is taken from this article):
tailrec fun calculateFact(acc: BigInteger, n: BigInteger): BigInteger {
if (n == BigInteger.ZERO) {
return acc
}
return calculateFact(n * acc, n - BigInteger.ONE)
}
fun calculateFact(n: BigInteger) : BigInteger {
return calculateFact(BigInteger.ONE, n)
}
fun main(args: Array<String>) {
val n: BigInteger = BigInteger(readLine())
val ans: BigInteger = calculateFact(n)
println("Factorial of $n is $ans")
}
This will work for numbers up to a couple hundred thousand, your problem with this one will become the time it takes to run instead of the memory constraints.
fun main(args:Array<String>) {
var no:Int = Integer.parseInt(readLine()) //read input from user and convert to Integer
var ans:Int=calculateFact(no) //call function and store to ans variable
println("Factorial of "+no+" is "+ans) //print result
}
fun calculateFact(no:Int):Int { //function for recursion
if(no==0) {
return 1
}
return (no*calculateFact(no - 1)) // you forgot to decrease the no here.
}
If you didnot decrease no then it will call the calculateFact() method all the time. Please check the code, it will work.

Resources