Kotlin: Pass ranges in function as arguments - kotlin

Hello is it possible to pass range in Kotlin function just like in python?
I've just started learning Kotlin but I am a little bit stuck
I wish i could pass somethind like
my_gauge = Gauge('test_name',1..200, 201..300, and etc.)
for example I have a Gauge object which rotates on the base
class Gauge(val gauge_name: String,
val red_value: Float,
val orange_value: Float,
val yellow_value: Float,
val green_value: Float,
var current_value: Float,
val min_value: Float,
val max_value: Float) {
val gauge_green = 0xFF66C2A5.toInt()
val gauge_yellow = 0xFFFDD448.toInt()
val gauge_orange = 0xFFF5A947.toInt()
val gauge_red = 0xFFD53E4F.toInt()
val min_rotation: Int = 0;
val max_rotation: Int = 300;
val ratio = max_rotation / max_value;
fun calculate_rotation(): Int {
return (current_value * ratio).toInt()
}
fun get_color(): Int {
if (current_value >= red_value) {
return gauge_red
}
if (current_value > orange_value) {
return gauge_orange
}
if (current_value > yellow_value) {
return gauge_yellow
}
return gauge_green
}
}
I've just realized that it wont work with this data instead it will be better to build my logic around ranges
So my question is How to pass ranges as a param in class/function (instead of floats)
PS: The function get_colors is not correct I will fix it once I can pass ranges with when(current_value) statement

Yes, the type of a range produced by .. is ClosedRange<T>:
fun foo(floatRange: ClosedRange<Float>) {
println(floatRange.random())
}
// Usage:
foo(1f..10f)
For integer ranges, you may prefer IntRange over ClosedRange<Int> because it allows you to use it without the performance cost of boxing by using first and last instead of start and endInclusive. There is no unboxed version for other number types.

Try this in simple way, you can use range according to data type IntRange, FloatRange, LongRange etc.
fun foo(range: IntRange){
for (a in range){
println(a)
}
}
// call this function by
foo(1..10)

Related

Kotlin: How to define a variable whose type depends on the input?

I have a function in Kotlin which takes a particular string as input. Depending on the input, I want to create a variable of a specific type and do some computations on it.
For example,
fun compute(input: String): Any{
if(input=="2d"){
var point: Point2D;// Points2D - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-1"){
var point: Point2DWithP1AsOrigin;// Point2DWithP1AsOrigin - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-2"){
var point: Point2DWithP2AsOrigin;
//initilize and do some computations
return point.findDistanceFromOrigin()
}
.
.
.
}
You can see in the above example, I want to initilize the type of point depending on the input and do computation and return.
All the if-else conditions have the same code except for the definition of the variable. How can I put all this in a single block with something like this:
var point: if(input=="2d) Point2D::class else if(input=="2d-1") Point2DWithP1AsOrigin::class.....
How can I do that?
You could do something like this
fun compute(input: String): Any{
val point: MyPoint = when(input) {
"2d" -> Point2D()
"2d-1" -> Point2DWithP1AsOrigin()
"2d-2" -> Point2DWithP2AsOrigin()
else -> Point2D() //fallback is necessary
}
//initilize and do some computations
return point.findDistanceFromOrigin()
}
But then it's essential that all those classes share the same interface. Because they need to have the same methods in order to do the same operations on them.
For example like this:
class Point2D : MyPoint {
override fun findDistanceFromOrigin() = 5
}
class Point2DWithP1AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 6
}
class Point2DWithP2AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 7
}
interface MyPoint {
fun findDistanceFromOrigin() : Int
}
You can store constructor references and then invoke required one
fun main() {
val constructors = mapOf(
"2d" to ::Point2D,
"2d-1" to ::Point2DWithP1AsOrigin,
"2d-2" to ::Point2DWithP2AsOrigin,
)
val type = "2d-2"
val constructor = constructors[type] ?: throw IllegalArgumentException("$type not supported")
val point = constructor()
println(point::class)
}
Output
class Point2DWithP2AsOrigin

Operator overloading on += for set and get calls wrong setter

I have made an extension functions for BigIntegers, allowing me to add Ints to them.
operator fun BigInteger.plus(other: Int): BigInteger = this + other.toBigInteger()
// Allowing me to do
val c = myBigInt + 3
I have also made a Counter class, holding bigintegers for various keys, for easy counting. Since doing counter["1"] += myBigInt isn't allowed on standard maps (it's nullable), I have added a custom getter that returns a default value, making this possible.
class Counter<K>(val map: MutableMap<K, BigInteger>) : MutableMap<K, BigInteger> by map {
constructor() : this(mutableMapOf())
override operator fun get(key: K): BigInteger {
return map.getOrDefault(key, BigInteger.ZERO)
}
I can then use it like this
val counter = Counter<String>()
c["ones"] += 5.toBigInteger()
Problem is that I cannot use it like this:
c["ones"] += 5 // doesn't work, "Kotlin: No set method providing array access"
but this should be equivalent to this, which works, since it should use my extension operator on the bigint:
c["ones"] = c["ones"] + 5 // works
Why doesn't this work?
I've tried adding a set method for Ints, but then I see a very weird behavior. Kotlin will do the calculation correct, but then convert the BigInteger to an Int before passing it to my class! Example:
inline operator fun BigInteger.plus(other: Int): BigInteger {
val bigInteger = this + other.toBigInteger()
println("calculated bigint to $bigInteger")
return bigInteger
}
class Counter<K>(val map: MutableMap<K, BigInteger>) : MutableMap<K, BigInteger> by map {
constructor() : this(mutableMapOf())
override operator fun get(key: K): BigInteger {
return map.getOrDefault(key, BigInteger.ZERO)
}
operator fun set(key: K, value: Int) {
println("setting int $value")
map[key] = value.toBigInteger()
}
}
val c = Counter<String>()
c["1"] = "2192039569601".toBigInteger()
c["1"] += 5
println("result: ${c["1"]}")
c["1"] = "2192039569601".toBigInteger()
c["1"] = c["1"] + 5
println("result: ${c["1"]}")
Which prints
calculated bigint to 2192039569606
setting int 1606248646 <--- why does it call the int setter here?
result: 1606248646
calculated bigint to 2192039569606
result: 2192039569606
Why does Kotlin do the BigInt summation, but converts it back to an Int before sending to my setter?
Update
Since a comment suggest this is a compiler issue, any other ideas?
My ultimate goal here, was to have a counter of big integers, but to be able to easily add ints to it.
Adding this as a set function, makes it being called for both ints and bigints, so I can do the proper assignment myself. However, it will also then allow someone to add floats that will crash at runtime.
operator fun set(key: K, value: Number) {
map[key] = when (value) {
is BigInteger -> value
is Int -> value.toBigInteger()
else -> throw RuntimeException("only ints")
}
}
Any tips?
Notice that c["ones"] += 5 can be translated into calls in two ways:
c.set("ones", c.get("ones").plus(5))
c.get("ones").plusAssign(5)
The first way is what your code currently translates to, because you don't have a plusAssign operator defined. As I said in the comments, there is a bug in the compiler that prevents the operators from resolved correctly. When resolving c["ones"] += 5, It seems to be trying to find a set operator that takes an Int instead (possibly because 5 is an Int), which is unexpected. If you modify the code in the bug report a little, you can even make it throw an exception when executed!
class Foo {
operator fun get(i: Int) : A = A()
operator fun set(i: Int, a: A) {}
operator fun set(i: Int, a: Int) {}
}
class A {
operator fun plus(b: Int) = A()
}
class B
fun main(args: Array<String>) {
val foo = Foo()
foo[0] = foo[0] + 1
foo[0] += 1 // this compiles now, since there is a set(Int, Int) method
// but A can't be casted to Int, so ClassCastException!
}
It is rather coincidental (and lucky) in your case, that the compiler knows how to convert from BigInteger (or any other Number type actually) to Int, using Number#intValue. Otherwise the program would have crashed too.
A natural alternative way is to define the plusAssign operator, so that the assignment gets translated the second way. However, we can't do it on BigInteger, because plusAssign would need to mutate this, but BigInteger is immutable. This means that we need to create our own mutable wrapper. This does mean that you lose the nice immutability, but this is all I can think of.
fun main() {
val c = Counter<String>()
c.set("1", "2192039569601".toMutableBigInteger())
c.get("1").plusAssign(5)
println("result: ${c["1"]}")
}
data class MutableBigInteger(var bigInt: BigInteger) {
operator fun plusAssign(other: Int) {
bigInt += other.toBigInteger()
}
}
fun String.toMutableBigInteger() = MutableBigInteger(toBigInteger())
class Counter<K>(val map: MutableMap<K, MutableBigInteger>) : MutableMap<K, MutableBigInteger> by map{
constructor() : this(mutableMapOf())
override operator fun get(key: K): MutableBigInteger {
return map.getOrPut(key) { MutableBigInteger(BigInteger.ZERO) }
}
operator fun set(key: K, value: Int) {
println("setting int $value")
map[key] = MutableBigInteger(value.toBigInteger())
}
}
Notably, getOrDefault is changed to getOrPut - when a value is not found, we want to put the zero we return into the map, rather than just returning a zero that is not in the map. Our changes to that instance wouldn't be visible through the map otherwise.

How to set return type of a function to mutableListOf in kotlin

I made a function which returns all factors of an integer. But the problem is that it gives an error that the return type is Unit instead of mutableListOf. my code:
fun get_factors(num: Int) {
var factors = mutableListOf<Int>()
for (x in 1..num) {
if (x % num == 0) {
factors.add(x)
}
}
return factors
}
fun main() {
print(get_factors(18))
}
I tried doing:
fun get_factors(num: Int): mustableListOf {
var factors = mutableListOf<Int>()
for (x in 1..num) {
if (x % num == 0) {
factors.add(x)
}
}
return factors
}
fun main() {
print(get_factors(18))
}
but it says mutableListOf not defined.
I just started learning Kotlin today so I am a total beginner with Kotlin. Please help me out with this.
You seem to have confused the type MutableList<Int>, with the function mutableListOf.
Since the type name is MutableList<Int>, you should do:
fun get_factors(num: Int) : MutableList<Int> {
...
}
Or, if the caller doesn't need to modify the list, you can just return List<Int> too:
fun get_factors(num: Int) : List<Int> {
...
}
I can see why this is confusing - to create an instance of a type, you normally just add () to the end of the type name, so if mutableListOf() creates a list, you'd think that mutableListOf is the type name. However, this is actually calling the global function called mutableListOf, which returns an instance of MutableList<T>.
One way to distinguish between these is to look at the first letter. Type names usually begin with a capital letter, whereas function names begin with a small letter.

How to understand a fun with = in Kotlin?

I know a standard fun just like Code 0.
The Code 1 is a sample code from webpage, I can't understand completely the
fun convertFromDomain(forecast: ForecastList) = with(forecast) {...}
Why is the symbol = added to the fun? and is the return value of the fun convertFromDomain unit ?
Code 0
fun My(forecast: ForecastList):Boolean {
...
return true;
}
Code 1
data class ForecastList(val id: Long, val city: String, val country: String, val dailyForecast: List<Forecast>) {
val size: Int
get() = dailyForecast.size
operator fun get(position: Int) = dailyForecast[position]
}
data class Forecast(val id: Long, val date: Long, val description: String, val high: Int, val low: Int,
val iconUrl: String)
fun convertFromDomain(forecast: ForecastList) = with(forecast) {
val daily = dailyForecast.map { convertDayFromDomain(id, it) }
CityForecast(id, city, country, daily)
}
Block body
Consider this function:
fun sum(a: Int, b: Int): Int {
return a + b
}
The behaviour is defined in a block body. It has an explicit return type (Int) and an explicit return statement. Both are mandatory here. If you don't specify a return type explicitely it will be Unit by default and since the inferred type of a + b is Int it won't compile.
Expression body
If you write it like this
fun sum(a: Int, b: Int) = a + b
you don't need to specify the return type because it can be inferred from the expression.You don't need a return statement either because the last expression is returned. What follows the = sign is called an expression body.
So, both functions do the same thing. The second one is only written more concise.
Note
A common mistake is to use them both at once like this:
fun sum(a: Int, b: Int) = { a + b }
What this would do becomes clear, if you specify the returned type explicitely:
fun sum(a: Int, b: Int): () -> Int = { a + b }
You would actually return a lambda of type () -> Int which is surely not what you want.
A function has usually the following form in kotlin:
fun name([parameters])[: return_type] {
// function-body
}
e.g.
fun doubleTheValue(number: Int): Int {
return number * 2
}
If your function-body is just a single-expression, you can use a shorter version of the function declaration
fun name([parameters])[: return_type] = [expression]
e.g.
fun doubleTheValue(number: Int): Int = nummber * 2
fun doubleTheValue(number: Int) = nummber * 2 // type can also be inferred
So it's nothing special, just a shorter version of a function declaration.
Traditional way to define a function is just like what you write in Code 0, which consists of function name, parameters, return type and the block body. In Kotlin, function can be defined with an expression body and the return type can be inferred from the expression body.
Suppose there is a function which convert Boolean to Int, in traditional way:
fun Boolean.toInt(): Int {
return if (this) 1 else 0
}
It can be simplified to:
fun Boolean.toInt() = if (this) 1 else 0
where the return type is inferred as Int because 1 and 0 are both Int which will be returned from the expression if (this) 1 else 0.

What's the fastest/simplest way to calculate a moving Average in Kotlin?

I can think on some dirty ways to calculate a moving average on Kotlin, but I'm not sure which one is the best. I know that kotlin has a lot of interesting features to work with collections and list. What do you think is the most efficient (or simplest) way to calculate a moving average?
Kotlin 1.2 will introduce a sliding window which you can combine with average obviously.
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3,1,List<Int>::average)
// OR
val movingAverage = data.windowed(3,1) { it.average() }
Until then you would have to introduce your own sliding sequence.
class SlidingSequence<out T>(val source: Iterable<T>,
val slideSize: Int,
val slideStep: Int) : Sequence<List<T>> {
override fun iterator(): Iterator<List<T>> = object : AbstractIterator<List<T>>() {
private val iterator = if (slideSize > 0) source.iterator() else emptyList<T>().iterator()
private var buffer = listOf<T>()
override fun computeNext() = when {
iterator.hasNext() -> {
buffer = buffer.drop(slideStep).let {
it + iterator.asSequence().take(slideSize - it.size)
}
setNext(buffer)
}
else -> done()
}
}
}
fun <T> Iterable<T>.windowed(size: Int,
step: Int = 1): Sequence<List<T>> {
return SlidingSequence(this, size, step)
}
// and then you can do
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3).map(List<Int>::average)
PS. I haven't looked at the code of Kotlin 1.2 windowed implementation, but since the function takes an immediate transform, I'm guessing the result is not lazy, where in the self implemented case above it's a lazy result, so you need to actually enumerate the sequence with something like .toList() to get the actual values.
Another one-line given period > 0 is:
data?.takeLast(period)?.reduce { v, d -> v + d}?: 0 / period
This also works if the data is empty or null due to takeLast() `s behaviour.