How to fill varargs with range? - kotlin

What is a proper way to fill varargs? My attempt looks like a bycile
at fist i construct range
then i convert it to list
then to intarray
then spread it
m.getColumns(*((count.. count + 35).toList().toIntArray()))
where getColums is a method which accepts colums indexes as varargs

Yeah, ranges are really far from arrays in this sense, it's rather hard to pass them in as vararg parameters.
You could create a function to convert them to IntArray instances one step quicker:
fun IntRange.toIntArray() = this.toList().toIntArray()
m.getColumns(*(count..count + 35).toIntArray())
A slightly better optimized version of this conversion:
fun IntRange.toIntArray(): IntArray {
val size = this.last - this.first + 1
var current = this.first
return IntArray(size) { current++ }
}
Or you could define an overloaded function that takes an IntRange and does the conversion to call the original:
fun getColumns(range: IntRange) = getColumns(*range.toList().toIntArray())
Again, this could also make use of the conversion method above for better performance:
fun getColumns(range: IntRange) = getColumns(*range.toIntArray())

You call varargs method with either a number of comma separated variables or with an array.
Unfortunately, there is no shortcut to making array from a range.
But, you can create an array directly:
m.getColumns(*IntArray(35) { count + it })

Related

Kotlin is not able to change var using a method

Could someone explain why can't I change the value of var in that case ?
fun main(args: Array<String>) {
var number = 3
changeNumber(number)
}
fun changeNumber(number: Int) {
number = 4 //here I see a warning "val cannot be reassigned"
}
By passing a "number" to your function you "pass-by-value" NOT "pass-by-reference", the function does not know where in memory your main number is stored, therefore it cannot change it's value
you can see more about the subject here and here
There is absolutely no way to do it directly. Kotlin copies a value for scalar types (Double, Float, Boolean, Int, etc.). So any internal changes are lost.
For others types Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.
So you can wrap up your number in for this example an IntegerHolder and change the value that is kept in the reference.
data class IntegerHolder(
var v:Int
)
fun main() {
var a:IntegerHolder = IntegerHolder(2)
changeNumber(a)// Echange a value
print(a.v)
}
fun changeNumber(a:IntegerHolder) {
a.v = 5
}
Just in case you find the other answers a bit confusing, I'll add that you don't need to know about what's a scalar or passed by value. Those are under-the-hood optimizations that the compiler does but don't change the logical behavior of your code.
Kotlin works only with references, not pointers. What you're trying to do is what you can do with pointers in a language like C or C++. In those languages, you can pass a pointer to a function. A pointer is not the value of a variable, but the memory address of the variable itself so other functions can modify what the variable address is pointing at.
That's flat out not supported in Kotlin. You can only pass references. You are passing the object that the variable is pointing to, but you can't do anything to that variable itself. You are not passing a copy of that object, so if that object is mutable, you could change the values of properties inside it and the original function could see those changes by inspecting the object again. But many simple classes like Int, Float, Double, and String are all immutable, so it's logically irrelevant that you aren't passing a copy (and that's why Kotlin under-the-hood can optimize by passing actual values for some of these, called "inline classes").
A couple of workarounds for this limitation:
Mutable wrapper class. Use this in as your variable type and function parameter type.
data class IntWrapper(var value: Int)
fun main(args: Array<String>) {
val number = IntWrapper(3)
changeNumber(number)
println(number.value)
}
fun changeNumber(number: IntWrapper) {
number.value = 4
}
Pass a function that can modify your variable. The setter function is the parameter for your function that changes the variable. (The difference between pointers and what we do here is that the function that changes the variable doesn't actually know that it's changing a variable. It's just calling the function that was passed to it, which could be doing anything it wants with the provided number.)
fun main(args: Array<String>) {
var number = 3
changeNumber { number = it }
println(number)
}
fun changeNumber(numberSetter: (Int)->Unit) {
numberSetter(4)
}
But it's not very often that you'll need to do one of these. It's more common to write functions that provide a return value, and you can use that value to reassign the variable. This strategy is more robust. It provides better encapsulation, which naturally makes your code less bug-prone.
fun main(args: Array<String>) {
var number = 3
number = produceNewNumber()
println(number)
}
fun produceNewNumber(): Int {
return 4
}

Is it possible to implement sequence programming with vararg in Kotlin?

I've been trying sequence programming for processing the data I get from the vararg argument. I want to multiply every number in the list and add it to the new array list. Is it possible to use sequences.
I attach the code below:
fun main() {
val number = asList(10, 20, 30, 40, 50)
print(number)
}
fun <T> asList(vararg input: T): List<T> {
val result = ArrayList<T>()
input.map {it * 2}.foreach(result.add(it))
return result
}
Here is the error I get:
enter image description here
Yes, it's possible to create a sequence from a vararg; I'll come back to that later.
First, the main problem in the code above is that, unfortunately, it can't be done generically.  The error you're getting is because T could be any type, and most types can't be multiplied, so the compiler is telling you that you can't do the * 2.
You might think of restricting T to subclasses of Number, but that doesn't help.  (Number is a very weak type; it doesn't let you do any arithmetic, probably because you can't tell what type the result would have to be, nor what rounding or overflow might occur.  All it lets you do is convert the value to specific types.)
But if you remove the type parameter and code it for a particular numeric type, such as Int, then it can work fine.
There are also spelling and syntax errors in the code around the foreach call.  Fixing those too gives e.g.:
fun asList(vararg input: Int): List<Int> {
val result = ArrayList<Int>()
input.map{ it * 2 }.forEach{ result.add(it) }
return result
}
That's doing a lot of unnecessary work, though; the map() already returns a list, so there's no point in creating a second list and copying to it element-by-element!  Also, the name is misleading.  So it could just be:
fun asListDoubled(vararg input: Int) = input.map{ it * 2 }
Your question mentioned sequences; but your code uses normal eager lists.  If you want a lazily-evaluated sequence, you can just add an asSequence() call, e.g.:
fun asSequenceDoubled(vararg input: Int) = input.asSequence().map{ it * 2 }
But note that this now returns a Sequence<Int>, not List<Int>, so you can go on and do further lazy operations on it.  (If you want a List<Int>, then you can just append a toList() call — but there's little point in using a sequence only for the doubling, as the sequence overhead is probably far higher than any saving.)

Adding char to List<Char> in kotlin

I am trying to create List<Char> from String in Kotlin but it seems there is no inbuilt function is provided by lib. Also casting will generate error. So here is what I am doing. Please let me know if I am missing something in question. (Or we can say converting string to List<Char> in Kotlin).
var stringVal = "ABC"
var genList:List<Char> = arrayListof()
var count = 0
while (stringVal.length == genList.size) {
// way to add stringVal to genList
count++
}
The answer given by #Moira is definitely the way to go here, I would accept it.
However, the question was about adding an element to a List<Char>, which isn't possible in Kotlin because a List is immutable and yours gets initialized as an empty one, so it will stay empty.
Use a MutableList<Char> and simply add single Chars to it if you need it:
fun main(args: Array<String>) {
var genList = mutableListOf<Char>()
genList.add('a')
genList.add('A')
genList.add('B')
genList.add('C')
println(genList)
}
Output:
[a, A, B, C]
val chars = "ABC".toList()
CharSequence has a to(Mutable)List extension function defined in kotlin.text.
fun CharSequence.toList(): List<Char>
Returns a List containing all characters.
kotlin-stdlib / kotlin.text / toList
fun CharSequence.toMutableList(): MutableList<Char>
Returns a MutableList filled with all characters of this char sequence.
kotlin-stdlib / kotlin.text / toMutableList
Kotlin's standard libraries have hundreds of utility functions like this, so chances are that most of the time what you want already exists.
Many standard types that conceptually model some sort of iterable data, but are not Iterable, have extensions defined on them that are equivalent to those in kotlin.collections.

Kotlin: Define function for vararg and collection

Let's say for examples sake that I wanted to write my own sum function, which can take either a collection of ints or vararg ints, like in the following:
fun sum(ints: Collection<Int>): Int {
var result = 0
for (i in ints)
result += i
return result
}
fun sum(vararg ints: Int) = sum(ints.toSet())
Is there a better/idiomatic way to define a function for both parameter types? In many cases I only use such functions for one or two element, so wrapping it with listOf() outside of the function every time seems clunky to me.
I think there is no a better way of doing that. You can either use your example or this one:
fun sum(ints: Collection<Int>) = sum(*ints.toIntArray())
fun sum(vararg ints: Int): Int {
var result = 0
for (i in ints)
result += i
return result
}
Is there a better/idiomatic way to define a function for both
parameter types?
Since both are different types so it's not possible with a function only. You approach is okay.
But you pass an Array as vararg argument using spread operator (*)

KCallable doesn't work in Kotlin when one of the parameters is vararg

I have an issue where I have a class that stores a KCallable<Any> and calls it using parameters passed in by an interpreter that's running a custom scripting language. This works for most functions when I use KCallable.call(), but it doesn't seem to properly handle functions with a vararg parameter, instead assuming that the parameter is an array of the given type. Is there any way I can work around this issue using some sort of reflection method to convert the input for the parameters? Here's my current code:
class KotlinFunction(function: KCallable<Any>) {
fun call(args: List<Any>) {
function.call(*args.toTypedArray())
}
}
given the function as class member:
fun concat(vararg xs: String) = xs.reduce{l,r -> l + r}
Using 3 parameters, I get the following error:
java.lang.IllegalArgumentException: Callable expects 1 arguments, but 3 were provided.
The way that the vararg argument works is by collecting the multiple values into an Array, and passing that into the function. Therefore, your function concat is actually a function that takes an Array<String> as its single argument, and a reference to it is of type KFunction1<Array<out String>, String>.
So to call it with your setup, what you need to do is pass in the Array representing the vararg arguments inside a List, making this Array the only argument going into the KCallable#call method after spreading the list:
val kf = KotlinFunction(::concat)
kf.call(listOf(arrayOf("a", "b", "c")))
class KotlinFunction(val function: KCallable<Any>) {
fun call(args: List<Any>) {
// Here, `call` will be invoked with one parameter, the Array,
// as that's the only element in the List
function.call(*args.toTypedArray())
}
}