Working on an Advent of Code puzzle I had found myself defining a function to transpose matrices of integers:
fun transpose(xs: Array<Array<Int>>): Array<Array<Int>> {
val cols = xs[0].size // 3
val rows = xs.size // 2
var ys = Array(cols) { Array(rows) { 0 } }
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
Turns out that in the following puzzle I also needed to transpose a matrix, but it wasn't a matrix of Ints, so i tried to generalize. In Haskell I would have had something of type
transpose :: [[a]] -> [[a]]
and to replicate that in Kotlin I tried the following:
fun transpose(xs: Array<Array<Any>>): Array<Array<Any>> {
val cols = xs[0].size
val rows = xs.size
var ys = Array(cols) { Array(rows) { Any() } } // maybe this is the problem?
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
This seems ok but it isn't. In fact, when I try calling it on the original matrix of integers I get Type mismatch: inferred type is Array<Array<Int>> but Array<Array<Any>> was expected.
The thing is, I don't really understand this error message: I thought Any was a supertype of anything else?
Googling around I thought I understood that I should use some sort of type constraint syntax (sorry, not sure it's called like that in Kotlin), thus changing the type to fun <T: Any> transpose(xs: Array<Array<T>>): Array<Array<T>>, but then at the return line I get Type mismatch: inferred type is Array<Array<Any>> but Array<Array<T>> was expected
So my question is, how do I write a transpose matrix that works on any 2-dimensional array?
As you pointed out yourself, the line Array(cols) { Array(rows) { Any() } } creates an Array<Array<Any>>, so if you use it in your generic function, you won't be able to return it when Array<Array<T>> is expected.
Instead, you should make use of this lambda to directly provide the correct value for the correct index (instead of initializing to arbitrary values and replacing all of them):
inline fun <reified T> transpose(xs: Array<Array<T>>): Array<Array<T>> {
val cols = xs[0].size
val rows = xs.size
return Array(cols) { j ->
Array(rows) { i ->
xs[i][j]
}
}
}
I don't really understand this error message: I thought Any was a supertype of anything else?
This is because arrays in Kotlin are invariant in their element type. If you don't know about generic variance, it's about describing how the hierarchy of a generic type compares to the hierarchy of their type arguments.
For example, assume you have a type Foo<T>. Now, the fact that Int is a subtype of Any doesn't necessarily imply that Foo<Int> is a subtype of Foo<Any>. You can look up the jargon, but essentially you have 3 possibilities here:
We say that Foo is covariant in its type argument T if Foo<Int> is a subtype of Foo<Any> (Foo types "vary the same way" as T)
We say that Foo is contravariant in its type argument T if Foo<Int> is a supertype of Foo<Any> (Foo types "vary the opposite way" compared to T)
We say that Foo is invariant in its type argument T if none of the above can be said
Arrays in Kotlin are invariant. Kotlin's read-only List, however, is covariant in the type of its elements. This is why it's ok to assign a List<Int> to a variable of type List<Any> in Kotlin.
Related
Is there a convenient way in Kotlin to iterate through an array, let's say IntArray, in reversed order with these 2 conditions:
do not create an additional reversed copy of the array.
I need a handle to an element like in Java's enhanced for.
The best I could get is adding an extension function, but this needs to be done for each type of array if I need it not only for IntArrays:
fun IntArray.forEachReversed(action: (Int) -> Unit): Unit {
for (i in indices.reversed()) action(this[i])
}
Is there a better way in Kotlin class library?
this needs to be done for each type of array if I need it not only for IntArrays:
I think this is unavoidable because of the way the JVM works. There are separate classes to represent each primitive type on the JVM. However, there are only 8 of them, so it shouldn't be too bad ;-)
For Collections, there is the asReversed() function, but it's not available for arrays:
val original = mutableListOf('a', 'b', 'c', 'd', 'e')
val originalReadOnly = original as List<Char>
val reversed = originalReadOnly.asReversed()
println(original) // [a, b, c, d, e]
println(reversed) // [e, d, c, b, a]
// changing the original list affects its reversed view
original.add('f')
println(original) // [a, b, c, d, e, f]
println(reversed) // [f, e, d, c, b, a]
To answer you question, you solution looks fine but if your are targeting primitive IntArray, LongArray, FloatArray etc you cannot come with a generic solution, as this classes are independent and only thing common is Iterator, but you cannot traverse the iterator in reverse order without making a copy(ListIterator supports reverse iteration though), but the closest you can get is to use Array<T> instead specific Array like below
fun <T> Array<T>.forEachReversed(action: (T) -> Unit){
for(i in indices.reversed()){ action(this[i]) }
}
val intArray = Array(2){ 0 }
val longArray = Array<Long>(2){ 0 }
intArray.forEachReversed { }
longArray.forEachReversed { }
As pointed out by #ajan.kali if you need primitive arrays there is not much you can do. I suppose you have to deal with arrays but, if this is not the case, you should prefer other data structures (more info here)
Returning to your question, if your are fine using generic arrays you could probably declare your iterator to iterate in reverse order:
class ReverseIterator<T>(val it: Iterable<T>) : Iterator<T> {
private var index = it.count() - 1
override fun hasNext() = index >= 0
override fun next(): T = try { it.elementAt(index--) } catch (e:
IndexOutOfBoundsException) { index -= 1; throw
NoSuchElementException(e.message) }
}
then your extension function will become:
fun <T> Iterable<T>.forEachReversed(action: (T) -> Unit) {
for(elem in ReverseIterator(this)) {
action(elem)
}
}
and then given an array you can invoke it this way:
intArrayOf(1, 2, 3).asIterable().forEachReversed {
println(it)
}
Not particularly happy with this, but with arrays there is not much you can do other to try avoiding them.
I understand that Kotlin is a statically-typed language, and all the types are defined at the compile time itself.
Here is a when expression that returns different types:
fun main(){
val x = readLine()?.toInt() ?: 0
val y = when(x){
1 -> 42
2 -> "Hello"
else -> 3.14F
}
println(y::class.java)
}
During runtime (Kotlin 1.3.41 on JVM 1.8) this is the output:
When x = 1, it prints class java.lang.Integer
When x = 2, it prints class java.lang.String
Otherwise, it prints class java.lang.Float
When does the compiler determine the type of y? Or, how does the compiler infers the type of y during compile-time?
Actually, the type of the when expression resolves to Any in this case, so the y variable can have any value. An IDE even warns you, that Conditional branch result of type X is implicitly cast to Any, at least Android Studio does, as well as Kotlin Playground.
The type of that variable for you is Any (as the smallest possible superclass for all that types), but underlying value is untouched.
What does it mean? You can safely access only properties that are common for all that types (so only properties available for Any type. And property ::class.java is available for all types.
See this example - I use some other types to good visualise what is it about.
abstract class FooGoo {
fun foogoo(): String = "foo goo"
}
class Foo: FooGoo() {
fun foo(): String = "foo foo"
}
class Goo: FooGoo() {
fun goo(): String = "goo goo"
}
class Moo {
fun moo(): String = "moo moo"
}
fun main(x: Int) {
val n = when (x) {
0 -> Foo()
1 -> Goo()
else -> throw IllegalStateException()
} // n is implicitly cast to FooGoo, as it's the closes superclass of both, Foo and Goo
// n now has only methods available for FooGoo, so, only `foogoo` can be called (and all methods for any)
val m = when (x) {
0 -> Foo()
1 -> Goo()
else -> Moo()
} // m is implicitly cast to Any, as there is no common supertype except Any
// m now has only methods available for Any() - but properties for that class are not changed
// so, `m::class.java` will return real type of that method.
println(m::class.java) // // Real type of m is not erased, we still can access it
if (m is FooGoo) {
m.foogoo() // After explicit cast we are able to use methods for that type.
}
}
During compile-time, the inferred type of y is Any which is the supertype of all types in Kotlin. During run-time, y can reference [literally] any type of object. The IDE generates a warning "Conditional branch result of type Int/String/Float is implicitly cast to Any".
In the example,
When x = 1, it refers to an object of type java.lang.Integer.
When x = 2, it refers to an object of type java.lang.String.
Otherwise, it refers to an object of type java.lang.Float.
Thanks Slaw for the quick explanation:
There's a difference between the declared type of a variable and the actual type of the object it references. It's no different than doing val x: Any = "Hello, Wold!";
I have come across the concept called destructuring declarations - when you can return multiple values from a function at once. It seems very convenient, but at the same time it looks like a tricky workaround. Each time when I think about that feature in Java, I understand that it's a hole in my architecture - there should probably be a class then, not just a couple of variables.
What do you think?
The concept allows having classes that clearly identify a few of their primary properties, the components.
Then you can access these components by using a destructuring declaration, without syntactic noise of accessing the properties.
Compare:
val point = clickEvent.getPointOnScreen()
val x = point.xCoordinate
val y = point.yCoordinate
// Use `x` and `y` in some calculations
and, assuming that the type has component1 and component2, just:
val (x, y) = clickEvent.getPointOnScreen()
Basically, it is not necessary to use this sort of syntactic sugar, and the concept itself does not harm any of the abstractions, it only provides a convenient way to access properties of a class instance in some cases when you don't need the instance itself.
Another example is working with map entries, e.g:
for ((key, value) in myMap) { /* ... */ }
There's still a Map.Entry<K, V> behind the (key, value) destructuring, and you can replace it by for (entry in myMap) ..., but usually it's the two properties that you need. This is where destructuring saves you from a little syntactic noise.
You can also define componentN function as extension for non data classes like this:
operator fun Location.component1() = latitude
operator fun Location.component2() = longitude
and when you want to process on list of locations, you can write this:
for ((lat, lon) in locations) {
......
}
What's the point of destructuring declarations in Kotlin?
Structuring, or construction, is creating an object from values in different variables. Destructuring is the opposite, to extract values into variables from within an existing object.
Part of the Kotlin philosophy is to be concise since the simpler and more concise the code is, the faster you’ll understand what’s going on. Destructuring improves readability which is part of being concise. Compare the following two snippets (let's consider the class Triple)
Without using destructuring
fun getFullName() = Triple("Thomas", "Alva", "Edison")
val result = getFullName()
val first = result.first
val middle = result.second
val last = result.third
Using destructuring
fun getFullName() = Triple("Thomas", "Alva", "Edison")
val (first, middle, last) = getFullName()
It is also possible to take advantage of destructuring to extract key and value from Map's entries.
for ((key, value) in aMap) {
/* ... */
}
Destructuring is the most useful when dealing with built-in data structures. Their fields have names making sense in the context of a data structure (handy when you're writing your own hashmap), but completely cryptic when you're dealing with the data contained there (which is 100% of the time, nobody writes their own hashmaps). Eg. Pair with it's first and second or Map.Entry with key and value.
Consider transforming Map values:
val myMap = mapOf("apples" to 0, "oranges" to 1, "bananas" to 2)
myMap
.asIterable()
.filter { it.value > 0 }
.sortedBy { it.key.length }
.joinToString(prefix = "We have ", postfix = " in the warehouse") {
"{$it.value} of ${it.key}"
}
To make it readable, you'd have to define intermediate variables:
myMap
.asIterable()
.filter {
val count = it.value
count > 0
}
.sortedBy {
val fruit = it.key
fruit.length
}
.joinToString(prefix = "We have ", postfix = " in the warehouse") {
val count = it.value
val fruit = it.key
"$count of $fruit"
}
Now it's readable, but at what cost?!?
Destructuring makes this cost more beareable:
myMap
.asIterable()
.filter { (fruit, count) -> count > 0 }
.sortedBy { (fruit, count) -> fruit.length }
.joinToString(prefix = "We have ", postfix = " in the warehouse") { (fruit, count) ->
"$count of $fruit"
}
That's the point.
In Kotlin documentation I found the following example:
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
Is it possible (and how) to do the similar with 2D matrix:
for ((i, j, value) in matrix2D.withIndex()) {
// but iterate iver double index: i - row, j - column
if (otherMatrix2D[i, j] > value) doSomething()
}
How to make support this functionality in Kotlin class?
While the solutions proposed by miensol and hotkey are correct it would be the least efficient way to iterate a matrix. For instance, the solution of hotkey makes M * N allocations of Cell<T> plus M allocations of List<Cell<T>> and IntRange plus one allocation of List<List<Cell<T>>> and IntRange. Moreover lists resize when new cells are added so even more allocations happen. That's too much allocations for just iterating a matrix.
Iteration using an inline function
I would recommend you to implement a very similar and very effective at the same time extension function that will be similar to Array<T>.forEachIndexed. This solution doesn't do any allocations at all and as efficient as writing nested for cycles.
inline fun <T> Matrix<T>.forEachIndexed(callback: (Int, Int, T) -> Unit) {
for (i in 0..cols - 1) {
for (j in 0..rows - 1) {
callback(i, j, this[i, j])
}
}
}
You can call this function in the following way:
matrix.forEachIndexed { i, j, value ->
if (otherMatrix[i, j] > value) doSomething()
}
Iteration using a destructive declaration
If you want to use a traditional for-loop with destructive declaration for some reason there exist a way more efficient but hacky solution. It uses a sequence instead of allocating multiple lists and creates only a single instance of Cell, but the Cell itself is mutable.
data class Cell<T>(var i: Int, var j: Int, var value: T)
fun <T> Matrix<T>.withIndex(): Sequence<Cell<T>> {
val cell = Cell(0, 0, this[0, 0])
return generateSequence(cell) { cell ->
cell.j += 1
if (cell.j >= rows) {
cell.j = 0
cell.i += 1
if (cell.i >= cols) {
return#generateSequence null
}
}
cell.value = this[cell.i, cell.j]
cell
}
}
And you can use this function to iterate a matrix in a for-loop:
for ((i, j, item) in matrix.withIndex()) {
if (otherMatrix[i, j] > value) doSomething()
}
This solution is lightly less efficient than the first one and not so robust because of a mutable Cell, so I would really recommend you to use the first one.
These two language features are used for implementing the behaviour that you want:
For-loops can be used with any class that has a method that provides an iterator.
for (item in myItems) { ... }
This code will compile if myItems has function iterator() returning something with functions hasNext(): Boolean and next().
Usually it is an Iterable<SomeType> implementation (some collection), but you can add iterator() method to an existing class as an extension, and you will be able to use that class in for-loops as well.
For destructuring declaration, the item type should have componentN() functions.
val (x, y, z) = item
Here the compiler expects item to have component1(), component2() and component3() functions. You can also use data classes, they have these functions generated.
Destructuring in for-loop works in a similar way: the type that the iterator's next() returns must have componentN() functions.
Example implementation (not pretending to be best at performance, see below):
Class with destructuring support:
class Cell<T>(val i: Int, val j: Int, val item: T) {
operator fun component1() = i
operator fun component2() = j
operator fun component3() = item
}
Or using data class:
data class Cell<T>(val i: Int, val j: Int, val item: T)
Function that returns List<Cell<T>> (written as an extension, but can also be a member function):
fun <T> Matrix<T>.withIndex() =
(0 .. height - 1).flatMap { i ->
(0 .. width - 1). map { j ->
Cell(i, j, this[i, j])
}
}
The usage:
for ((i, j, item) in matrix2d.withIndex()) { ... }
UPD Solution offered by Michael actually performs better (run this test, the difference is about 2x to 3x), so it's more suitable for performance critical code.
The following method:
data class Matrix2DValue<T>(val x: Int, val y: Int, val value: T)
fun withIndex(): Iterable<Matrix2DValue<T>> {
//build the list of values
}
Would allow you to write for as:
for ((x, y, value) in matrix2d.withIndex()) {
println("value: $value, x: $x, y: $y")
}
Bear in mind though that the order in which you declare data class properties defines the values of (x, y, value) - as opposed to for variable names. You can find more information about destructuring in the Kotlin documentation.
If I create an array, then fill it, Kotlin believes that there may be nulls in the array, and forces me to account for this
val strings = arrayOfNulls<String>(10000)
strings.fill("hello")
val upper = strings.map { it!!.toUpperCase() } // requires it!!
val lower = upper.map { it.toLowerCase() } // doesn't require !!
Creating a filled array doesn't have this problem
val strings = Array(10000, {"string"})
val upper = strings.map { it.toUpperCase() } // doesn't require !!
How can I tell the compiler that the result of strings.fill("hello") is an array of NonNull?
A rule of thumb: if in doubts, specify the types explicitly (there is a special refactoring for that):
val strings1: Array<String?> = arrayOfNulls<String>(10000)
val strings2: Array<String> = Array(10000, {"string"})
So you see that strings1 contains nullable items, while strings2 does not. That and only that determines how to work with these arrays:
// You can simply use nullability in you code:
strings2[0] = strings1[0]?.toUpperCase ?: "KOTLIN"
//Or you can ALWAYS cast the type, if you are confident:
val casted = strings1 as Array<String>
//But to be sure I'd transform the items of the array:
val asserted = strings1.map{it!!}
val defaults = strings1.map{it ?: "DEFAULT"}
Why the filled array works fine
The filled array infers the type of the array during the call from the lambda used as the second argument:
val strings = Array(10000, {"string"})
produces Array<String>
val strings = Array(10000, { it -> if (it % 2 == 0) "string" else null })
produces Array<String?>
Therefore changing the declaration to the left of the = that doesn't match the lambda does not do anything to help. If there is a conflict, there is an error.
How to make the arrayOfNulls work
For the arrayOfNulls problem, they type you specify to the call arrayOfNulls<String> is used in the function signature as generic type T and the function arrayOfNulls returns Array<T?> which means nullable. Nothing in your code changes that type. The fill method only sets values into the existing array.
To convert this nullable-element array to non-nullable-element list, use:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
Which is fine because your map call converts to a list anyway, so why not convert beforehand. Now depending on the size of the array this could be performant or not, the copy might be fast if in CPU cache. If it is large and no performant, you can make this lazy:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asSequence().filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
Or you can stay with arrays by doing a copy, but really this makes no sense because you undo it with the map:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings: Array<String> = Array(nullableStrings.size, { idx -> nullableStrings[idx]!! })
Arrays really are not that common in Java or Kotlin code (JetBrains studied the statistics) unless the code is doing really low level optimization. It could be better to use lists.
Given that you might end up with lists anyway, maybe start there too and give up the array.
val nullableStrings = listOf("a","b",null,"c",null,"d")
val strings = nullableStrings.filterNotNull()
But, if you can't stop the quest to use arrays, and really must cast one without a copy...
You can always write a function that does two things: First, check that all values are not null, and if so then return the array that is cast as not null. This is a bit hacky, but is safe only because the difference is nullability.
First, create an extension function on Array<T?>:
fun <T: Any> Array<T?>.asNotNull(): Array<T> {
if (this.any { it == null }) {
throw IllegalStateException("Cannot cast an array that contains null")
}
#Suppress("CAST_NEVER_SUCCEEDS")
return this as Array<T>
}
Then use this function new function to do the conversion (element checked as not null cast):
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asNotNull() // magic!
val upperStrings = strings.map { it.toUpperCase() } // no error
But I feel dirty even talking about this last option.
There is no way to tell this to the compiler. The type of the variable is determined when it is declared. In this case, the variable is declared as an array that can contain nulls.
The fill() method does not declare a new variable, it only modifies the contents of an existing one, so it cannot cause the variable type to change.