Multidimensional array of Objects in Kotlin - arrays

I'm new in Kotlin, and I want to create a multi dimensional array of a custom class, with null permitted. Something like that
private var array_map = arrayOf<Array<Obstacle?>>()
...
array_map[1][2] = Obstacle()
How can I do it? Thank you!

In case you need the index of each element in the constructor of the elements of the array:
Declaration:
var matrix: Array<Array<Obstacle?>>
Instantiation and initialization:
matrix = Array(numRows) { row ->
Array(numCols) { col ->
Obstacle(row, col)
}
}

You can use private var arrayMap: Array<Array<Obstacle?>> = arrayOf(). Just wrap with as much Array<> as you need.

Not sure if this is what you want, but imagine that Obstacle is a custom class with a field num as below
data class Obstacle(var num: Int){}
A 2D array of the Obstacle object would be as below:
val array: Array<Obstacle?> = arrayOf(Obstacle(123), Obstacle(234))
val arrayOfArray: Array<Array<Obstacle?>> = arrayOf(array)
println(arrayOfArray[0][0]) // would print Obstacle(num=123)
println(arrayOfArray[0][1]) // would print Obstacle(num=234)
So you should be declaring your 2D array as below
val arrayOfArray: Array<Array<Obstacle?>> = arrayOf()

Your code will compile as is. The problem is just that array size can't be changed and arrayOf<Array<Obstacle?>>() creates an empty array, so array_map[1][2] = Obstacle() fails at runtime. (Unless you do array_map = ... somewhere between them. Note that you should prefer val arrayMap, which can't be reassigned, unless you have a specific reason to use var.)
If you want your array to start with nulls, there is arrayOfNulls in the standard library, but it only creates a single-dimensional array, and what you really need is an array of arrays of nulls. You can write a helper function:
inline fun <reified T> matrixOfNulls(n: Int, m: Int) = Array(n) { arrayOfNulls<T>(m) }
private val arrayMap = matrixOfNulls<Obstacle>(5, 5) // example arguments

The approach I always use for this case is:
arr2D = Array(sizeA) { Array(sizeB) { content } }
Note I replaced the sizes by fields names to illustrate that each number/field represents the width and height length of each dimension of the 2D array.
Also, content should be replaced by the main content you want to fill in each coordinate, in your case seems you aims to setup with Obstacle() instances. If you want fill this content in other moment put null or a quick Any() reference.
In this last case, after creating that you can simply perform to set the itens:
arr2D[1][2] = Obstacle()

Related

Array of array double won't adding a new element in kotlin

I have array of array double but it won't add element after using .plusElementor .plus. code below inside from view model that returns it.data which is a list of object
Code
var ageEntry : Int
val dataObject : Array<Array<Double>> = arrayOf()
for (dataWeight in it.data!!){
ageEntry = dataWeight.date.toLocalDate().getAgeInMonth().toString().toInt()
dataObject.plusElement(arrayOf(ageEntry.toDouble(), dataWeight.weight.toDouble()))
Log.d("DATA_SERIES_BARU", "setupViewInstance: ${dataObject.contentToString()}")
}
Log
The OP's proposed answer is subpar to say the least. If you need a mutable data structure, use a list not an array. I suggest something like this:
it.data?.fold(ArrayList<Array<Double>>()) { list, dataWeight ->
val ageEntry = dataWeight.date.toLocalDate().getAgeInMonth().toString().toInt()
list.add(arrayOf(ageEntry.toDouble(), dataWeight.weight.toDouble()))
list
}
If you absolutely need an array at the end, you can easily convert it using toTypedArray().
Im adding this function to add array Element
fun <T> appendArray(arr: Array<T>, element: T): Array<T?> {
val array = arr.copyOf(arr.size + 1)
array[arr.size] = element
return array
}
then you can call it
appendArray(copyDataObject, arrayOf(ageEntry,arrayOf(arrayOf(2.0, 3.0)))

C# - Tuple arrays are mutable, but tuple lists are not. How do I get around this?

I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.
Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable
So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.
static void Main()
{
List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
(int, float)[] arr2 = new (int, float)[1];
arr1[0].Item1 += 1; // This line
arr2[0].Item1 += 1;
}
Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?
Why are tuple arrays mutable, but lists are not?
The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.
The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)
If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:
var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;
Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:
public void Method(ref int x) => x++;
public void CallMethod()
{
var list = new List<int> { 0 };
var array = new int[] { 0 };
Method(ref list[0]); // Error
Method(ref array[0]); // Valid
}

Is array declaration in Kotlin with size possible just with initialization?

I didn't find how to declare in Kotlin an array with predefined size without initializate it.
This is OK:
lateinit var v:Array<Int>
But I guess that one cannot put a size specification in array type.
If one needs to specify a size. one have to do:
var v2:Array<Int> = Array<Int>(2){5}
In this case, all elements of the vector are equal to 5
Below there is a example with classes and arrays:
data class But(
val fufo: Int=0,
val tp: Int = 1
)
typealias ArBut = Array<But>
data class CArray (
var arrayC: ArBut = ArBut(2){But()}
)
val a = CArray(arrayOf(But(2,2),But(5,4),But(3,3)))
println(a.arrayC[2])
It works! The interesting part is that how the initialization is not part of type, you can put arrays of any size in the class without bounding check. It would be different if the size was part of type spec.
Now an exemple, using matrix. Notice that the syntax is a little bit intricate.
data class CMatr (
val matrC: Array<ArBut> = Array<ArBut>(2){ArBut(0){But()}}
)
val m = CMatr(arrayOf( arrayOf(But(2,2),But(5,4)),
arrayOf(But(-2,2),But(3,4)), arrayOf(But(1,1),But(5,3)) ))
println(m.matrC[2][1]) // Also works!
Is it impossible put size in array type specification or I'm missing something?
for primitive types :
this is how you do it. instead of using kotlin built-in functions like intArrayOf(args...) you use the constructor for IntArray
here is the example :
// Array of integers of a size of N
val arr = IntArray(N)
// Array of integers of a size of N initialized with a default value of 2
val arr = IntArray(N) { 2 }
for reference types :
for reference type objects you can do
val cars: Array<Car?> = arrayOfNulls(N)
//returns an array of nullable Car objects with null values and size of N
and if you want to an array of non null objects you need to initialize them when creating array
val cars: Array<Car> = Array<Car>(5){ Car() }
//returns an array of non nullable car objects that has been initialized
//with the method you provided in this case Car constructor with size of N
Yes, array size is not part of its type in Kotlin and there's no way to make it a part. This isn't specific to arrays; types can't depend on values in any way in Kotlin.
Size initialization in the type allow checking bound violation in runtime.
Array bounds are always checked at runtime on JVM. Even if a compiler wanted not to do it, it can't.
For your example, with the Butclass, you could use:
var arrayC: Array<But?> = arrayOfNulls(2) // no initialization required
or:
var arrayC: Array<But> = Array<But>(2){But()} // initialization required
But either way will not forbbid you of creating a new instance of a bigger array and assign it to the variable.
EDIT
The way I see it, there are two approaches to solve this.
The first would be to declare your array property as a var and test the assignement in your setter:
class Test {
var array: Array<Int> = Array(3){0}
set(value) {
if(value.size > 3)
throw IllegalArgumentException("The array size cannot be bigger than 3")
field = value
}
}
fun main(args: Array<String>) {
val test = Test()
test.array = arrayOf(0, 1, 2) // Ok
test.array = arrayOf(0, 1, 2, 3) // throws IllegalArgumentException
}
Or, if you want to deal with it at compile time, you can make your property final and initialize it with the size you want.
class Test {
val array: Array<Int> = Array(3){0}
}
fun main(args: Array<String>) {
val test = Test()
for (i in 0..2) // Ok
test.array[i] = i
for (i in 0..3) // throws ArrayIndexOutOfBoundsException
test.array[i] = i
test.array = arrayOf(0, 1, 2, 3) // compile time error: Val cannot be reassigned
}

Multidimensional-array in Ceylon

I would like to work in Ceylon with a multidimensional array. Is this planned in Ceylon? If so, how can I declare it?
I would like to use this construct in Ceylon, as shown here in Java:
int x = 5;
int y = 5;
String[][] myStringArray = new String [x][y];
myStringArray[2][2] = "a string";
First, consider whether you really need an array (i.e. something with fixed length and modifiable elements), or whether a list (or list of lists) or a map might be better. Though from your example, you seem to need modification.
In the JVM, a "multidimensional" array is just an array of arrays.
In Java, new String[y] creates an array filled with null entries, which is not an allowed value of type String in Ceylon. So you can either have an array of String? (which allows null), or pre-fill your array with some other value, using e.g. Array.ofSize(...):
Array.ofSize(y, "hello")
The same is valid for arrays of arrays. We could do this:
value myStringArray = Array.ofSize(x, Array.ofSize(y, "hello"));
Though this would have the same array in each "row" of the 2D-array, which is not what we want (as replacing myStringArray[2][2] would replace all entries with a 2 as the second coordinate). Here the other Array constructor is useful, which takes an iterable:
value myStringArray = Array({ Array.ofSize(y, "hello") }.repeat(x));
This takes advantage of the fact that the iterable enumeration evaluates its arguments lazily, and thus the array constructor will get x different elements.
I like Paulo's answer, but here's an alternative approach, which allows us to use a comprehension to populate the 2D array:
//the size of the square 2D array
value n = 5;
//create it using a nested comprehension
value arr = Array {
for (i in 1..n-1) Array {
for (j in 0..n-1)
i==j then 1 else 0
}
};
//display it
for (row in arr) {
printAll(row);
}

Deep copy of 2D array in Scala?

How do I do a deep copy of a 2D array in Scala?
For example
val a = Array[Array[Int]](2,3)
a(1,0) = 12
I want val b to copy values of a but without pointing to the same array.
You can use the clone method of the Array class. For a multi-dimensional Array, use map on the extra dimensions. For your example, you get
val b = a.map(_.clone)
Just transpose it twice
a.transpose.transpose
Given:
val a = Array[Array[Int]]
you could try:
for(inner <- a) yield {
for (elem <- inner) yield {
elem
}
}
A deeper question is WHY you would want do do so with ints? The whole point of using immutable types is to avoid exactly this kind of construct.
If you have a more generic Array[Array[T]], then your main concern is how to clone the instance of T, not how to deep-clone the array.

Resources