I have a question about Kotlin.
I tried two versions of Kotlin, 1.0.0 and 1.2.6.
Using Kotlin, we can initialize an array and access to its element like this.
val n: Int = 10
val arr = Array(n, { it } )
val i: Int = 0
println(arr[i])
However, I got an error with this code.
val n: Long = 10
val arr = Array(n, { it } )
val i: Long = 0
println(arr[i])
It seems that it is an only way to cast Long to Int in order to compile this code.
val n: Long = 10
val arr = Array(n.toInt(), { it } )
val i: Long = 0
println(arr[i.toInt()])
However, it seems too redundant to me, but I couldn't find any solutions. So my question is
Is there any way to initialize arrays and access elements with a Long
variable?
Does Kotlin have any reasons that Long variable should not be accepted here?
Kotlin comes with longArrayOf(1, 2, 3) which will create an array for you which contains Longs.
Note that what you are trying to do with println(arr[i]) is getting a Long value out of arr, but the indexing of arrays is done with Ints. It will never work with Longs:
/**
* Returns the array element at the given [index].
* This method can be called using the index operator.
*/
public operator fun get(index: Int): Long
If you want to initialize an array of longs of the given length, you can use the same top-level Array function:
val n = 10 // n is Int
val arrayOfLongs = Array(n) { it.toLong() } // Array of 10 longs
Here the number n is Int and the initializer function converts the integer index it of an element being initialized to Long, therefore we get an array of longs as the result.
Or you can use another similar function to create a specialized LongArray:
val longArray = LongArray(n) { it.toLong() } // LongArray of 10 longs
Both arrays store longs, but the latter does it more compactly.
Related
I want to have a class that stores three sets of 30 Foos each. I can declare them as arrays of Foo but I don't know how I can initialize them (give them default values) with 30 elements.
data class Container (
val first: Array<Foo>,
val second: Array<Foo>,
val third: Array<Foo>,
)
data class Foo (val a: Int, val b: Int)
There aren't too many ways to create an array in Kotlin and they are pretty straightforward. Depending on your needs, you can either use arrayOf() function, Array() constructor or create List first and then convert it into array.
Example with arrayOf():
val first = arrayOf(
Foo(0, 0),
Foo(1, 1),
...
)
Array():
val first = Array(30) { Foo(it, it) }
List:
val firstList = mutableListOf<Foo>()
firstList += Foo(0, 0)
firstList += Foo(1, 1)
...
first = firstList.toTypedArray()
If the code for generating these arrays is complicated, you can write it inside init {} block or create static function(s) that provides these arrays.
Given a maximum list size in parameter size and total amount of elements in parameter elements, I need to create a list of lists. What is the syntax for creating variables in for loops in Kotlin?
The way I'm thinking of going about this is to declare and create lists before elements are added to a list. Then, when a list has reached full capacity, it is switched out for the next list that is empty.
Here is the half-baked code:
fun listOfLists(size: Int, vararg elements: String): List<List<String>> {
var amountOfElements = elements.size
var currentSubList: List<String> = mutableListOf<String>()
val numberOfLists: Int = amountOfElements / size + 1
for (n in 0..numberOfLists) {
// Code for creating the total number of lists needed
}
for (e in elements) {
if (amountOfElements % size == 0) {
// Code for switching lists
}
amountOfElements--
}
As #dyukha correctly mentioned, what you need is chunked() function.
fun listOfLists(size: Int, vararg elements: String) =
elements.asList().chunked(size)
Or, if you want to be really efficient, you can also use asSequence():
fun listOfLists(size: Int, vararg elements: String) =
elements.asSequence().chunked(size)
chunked() doesn't work on Array, because it's defined on Iterable and Sequence, and Array doesn't implement any of them.
I'm trying to initialize an IntArray in Kotlin like so:
intArrayOf(1..9)
But I get a TypeError that Int is required, but I'm providing an IntRange. Is there a way to initialize the array with a range, or do I have to explicitly write out each value?
Using built in functions, this is how you could get to an IntArray from an IntRange:
val array: IntArray = (1..9).toList().toIntArray()
This is a bit wasteful, because it first constructs a list where it puts all the elements, and then it constructs an array as well. To do this directly, you could use your own extension, something like...
fun IntRange.toIntArray(): IntArray {
if (last < first)
return IntArray(0)
val result = IntArray(last - first + 1)
var index = 0
for (element in this)
result[index++] = element
return result
}
Which would give you this syntax:
val array: IntArray = (1..9).toIntArray()
This question already has an answer here:
kotlin int boxed identity
(1 answer)
Closed 4 years ago.
I am a beginner of kotlin.
I do not understand the output below.
#Test
fun testNumberBoxing() {
val a:Int = 1000
val boxedA1: Int? = a
val boxedA2: Int? = a
println("first check = ${boxedA1 === boxedA2}")
val b: Int = 2
val boxedB1: Int? = b
val boxedB2: Int? = b
println("second check = ${boxedB1 === boxedB2}")
}
result is
first check = true
second check = false
Why are the two outputs different?
my kotlin version is 1.2.31
org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.31
The output I got
first check = false
second check = true
What the code compiles to
public static final void main(#NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
int a = 1000;
Integer boxedA1 = Integer.valueOf(a);
Integer boxedA2 = Integer.valueOf(a);
String var4 = "first check = " + (boxedA1 == boxedA2);
System.out.println(var4);
int b = 2;
Integer boxedB1 = Integer.valueOf(b);
Integer boxedB2 = Integer.valueOf(b);
String var7 = "second check = " + (boxedB1 == boxedB2);
System.out.println(var7);
}
Why valueOf is not consistent
For this we need to look at the JavaDoc of valueOf:
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
As you can see, for small values it will return the same object on both calls, so they are equal, and for the larger uncached value the 2 objects are different
In java the == checks for object equality, so the 2 equal objects are false, while 2 copies of the same object returns true.
That's rather weird, I'm consistently (both locally and on try.kotlinlang.org with different Kotlin versions) getting this result instead:
first check = false
second check = true
And this is what is to be expected, as the JVM caches Integer instances int the -127 to 128 range, reusing the same Integer instance when one is required for boxing, literals, or Integer.valueOf calls in this range.
In contrast to php or javascript where === is in most cases the more sane option, in Kotlin === compares references to objects instead of values.
As others pointed out, objects for Integers of the same value can be cached. Same goes for Strings and the other primitive types.
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.