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 (*)
Related
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
}
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.)
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.
I am trying to create a swap function which takes in two parameters as shown below:
fun swap(a :Int, b:Int) {
}
I call it like this:
var a = 10
var b = 5
swap(a,b)
// a should be 5
// b should be 10
The problem is that even if I swap the values inside the swap function it won't be reflected on the caller's side because it is passed as a copy and not as a reference.
Is there anyway to pass value types to swap function and allow the function the ability to change them.
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 any other type, Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.
There is no way to change this behaviour.
After trying many ways to overcome the impossibility of passing scalar by reference, as happens in Kotlin, Java and some other languages; my current strategy is using for any scalar type a plain and generic wrap, as an above comment suggest.
Recently, I'm using this trick for everything, including inside a function that otherwise would demand that I return multiple values. The alternative is joining the returns in a artificial class or destructuring declarations: val (a, b, c) = function-call() syntax. However, I hate articial classes and destructuring declaration is for local variables only, and it's annoying when some needs visibility out of current block of commands.
My code is very simple:
data class p<T>( // It's a generic wrap class for scalar type T
var v:T
)
fun <T>swap(a:p<T>, b:p<T>){ // It's a generic swap for scalar types
var aux:p<T> = a.copy()
a.v = b.v
b.v =aux.v
}
fun main() {
var a:p<Int> = p<Int>(2) // 'a' is a kind of 'Int' variable
var b:p<Int> = p<Int>(3) // and so is 'b'
swap(a,b) // Exchange 'a' and 'b' values
println(a.v) // 3
println(b.v) // 2
}
The only drawback is not being able to use syntax sugar of a real scalar type.
I am forced to add .v on any use of a scalar variable.
I only uses that for variables that I need pass by reference in some function and it's not so common. I try, when possible, avoid collateral effects.
You can have a function that gets the references of variables
var x = 10
var y = 20
fun main() {
println("x=$x, y=$y") // x=10, y=20
swap(::x, ::y)
println("x=$x, y=$y") // x=20, y=10
}
fun <T> swap(firstRef: KMutableProperty0<T>, secRef: KMutableProperty0<T>) {
val temp = firstRef.get()
firstRef.set(secRef.get())
secRef.set(temp)
}
and you can pass the references of properties of some class like this swap(someClass::x, someClass::y)
the only limitation is that you can't pass references of local variables which is not the end of the world.
if you don't like the messy syntax you can always define a typealias and make it pretty:
typealias Ref<T> = KMutableProperty0<T>
fun <T> swap(firstRef: Ref<T>, secRef: Ref<T>) {
...
}
I know that OP didn´t ask for this, but idiomatic Kotlin would look like:
var a = 1
var b = 2
a = b.also { b = a }
Seems like Kotlin behaves pretty much like Java does:
Is Kotlin "pass-by-value" or "pass-by-reference"?
simple way to swap is make support class
private fun swap(pair: Pair) {
pair.a += pair.b
pair.b = pair.a - pair.b
pair.a = pair.a - pair.b
}
private data class Pair(var a: Int, var b: Int)
fun main() {
val pair = Pair(10, 5)
swap(pair)
println(pair)
}
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 })