You are already familiar with one-dimensional arrays. Now we’re going to look at multi-dimensional arrays with two or even more dimensions in Kotlin.
An array of arrays
First, let's figure what we mean by a multi-dimensional array.
Basically, we can say that a multi-dimensional array is an array of arrays. That is, in order to create a multidimensional array, we need to present an array as an element of another array. Eventually, we get a multi-dimensional array.
It makes it very easy to represent things that have many dimensions: for example, 3D objects with length, height, and width. The universe we live in could be described with four measurements, time being the fourth dimension, so it is 4D. Higher levels like 5D and so forth are hard to imagine, but when you put it into practice, they turn out to be handy and not too hard!
Let's look at some more down-to-earth examples. A seat in the theater can be indicated with a 2D-array: one index for the row, and another for the number of the seat in that row. If you want to write a game that uses maps such as Sea Battle, two-dimensional arrays will be very helpful in setting coordinates on the map. In addition, some mathematical structures are conveniently represented as multi-dimensional arrays.
First, let’s take a look at a special case of a multi-dimensional array that is used quite often in practice: a two-dimensional array.
Creating 2-dimensional arrays
If a one-dimensional array can be represented as a single sequence of elements, then an intuitive way of representing a two-dimensional array is a matrix or a table. If you're working with matrices or tables in your program, it makes sense to present them in the form of two-dimensional arrays.
Let's create a two-dimensional array of Int with 3 rows and 4 columns where all elements are 0's (zeros). Here is what it looks like:
val array2D = arrayOf(
arrayOf(0, 0, 0, 0),
arrayOf(0, 0, 0, 0),
arrayOf(0, 0, 0, 0)
)
You simply define each element of the array2D as an array of four zeros! It is easy to picture it like this:
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
We can say that the arrays with four zero elements are nested in the array2D. The main array that contains other arrays is called the main array.
Note an interesting feature: nested arrays do not necessarily have to be the same size. In the example below, each new embedded array has different lengths:
val array2D = arrayOf(
arrayOf(0),
arrayOf(1, 2),
arrayOf(3, 4, 5))
You can create nested arrays with different numbers of elements in the same 2D array.
And if you need to create an empty multidimensional array of Int, for example, you can do it like this:
val empty2DInt = arrayOf<Array<Int>>()
We'll look at this in more detail later.
Accessing elements
Let’s see how we can access an element of an array. The principle is exactly the same as for one-dimensional arrays. Only now we have to write two indices: first the index of the element of the main array, and then the index of the nested array.
Let's get back to our array2D for a moment. Suppose we need to access an element that is in the first row and the first column. How do we find this particular element? As you recall, a 2D array is an array of arrays. So, start by selecting one of the nested arrays by its index in the main array. The principle is similar to a 1D array.
First, go to the nested array and choose the inner array with its index:
val array2D = arrayOf(
arrayOf(0, 1, 2), // [0]
arrayOf(3, 4, 5) // [1]
)
array2D[0] | 0 | 1 | 2 |
array2D[1] | 3 | 4 | 5 |
Second, in this nested array, choose the required element with its index. This is also like in simple arrays:
array2D[0][0] | array2D[0][1] | array2D[0][2] |
0 | 1 | 2 |
Let's print array2D[0][0]: the element of the first row and the first column of our array2D:
val array2D = arrayOf(
arrayOf(0, 1, 2),
arrayOf(3, 4, 5)
)
println(array2D[0][0]) // 0
Remember that in all arrays indexing starts with 0!
The following code will show all the elements of the two-dimensional array array2D:
print(array2D[0][0]) // 0
print(array2D[0][1]) // 1
print(array2D[0][2]) // 2
print(array2D[1][0]) // 3
print(array2D[1][1]) // 4
print(array2D[1][2]) // 5Creating 2D arrays of different types
Nested arrays don't need to be of the type Int: as you remember, Kotlin provides various types of arrays. For example, you can create an array of string arrays, as in the example below:
You also can clearly define the type of elements of nested arrays:
val arrayOfString2D = arrayOf(
arrayOf<String>("to", "be", "or"),
arrayOf<String>("not", "to", "be")
)
It is better to explicitly define the type of arrays using the arrayOf() constructor where necessary.
In order to create nested arrays of primitives, you can use arrays of a certain type, as we did for one-dimensional arrays: IntArray, LongArray, DoubleArray, FloatArray, CharArray, ShortArray, ByteArray, BooleanArray.
For example, let's consider creating an array of the character type:
val arrayOfChar2D = arrayOf(
charArrayOf('A', 'R', 'R'),
charArrayOf('A', 'Y', 'S')
)
You can imagine it like this:
A | R | R |
A | Y | S |
Nested arrays can be of different types. For example, you can create a two-dimensional array that stores both Int and String arrays:
val arrayOfString2D = arrayOf(
arrayOf("Practice", "makes", "perfect"),
arrayOf(1, 2)
)
You can create nested arrays of different types in the same 2D array.
Features of working with 2D arrays
Let’s look at some useful and interesting features of working with two-dimensional arrays. You remember that we can print all the elements of the array as a string using the joinToString() function. For nested arrays, it will also work. Only now you must specify the index of the nested array that you want to convert to a string:
val arrayString = arrayOf(
arrayOf("A", "R", "R", "A", "Y")
)
print(arrayString[0].joinToString()) // A, R, R, A, Y
In the case of multi-dimensional arrays, this will not always be convenient. In order to get all array contents in a single string, you can use the function contentDeepToString():
val arrayOfChar2D = arrayOf(
charArrayOf('k'),
charArrayOf('o', 't'),
charArrayOf('l', 'i', 'n'))
println(arrayOfChar2D.contentDeepToString()) // [[k], [o, t], [l, i, n]]Multi-dimensional arrays (>2)
We are finally ready to deal with more complex concepts. There are arrays with more than two dimensions. Even though it is more difficult to understand what it looks like, don’t worry: you will get used to working with them.
You can imagine a three-dimensional array like this:
[0, 1] | [2, 3] |
[4, 5] | [6, 7] |
In each element of a two-dimensional array, you have another nested array.
You can imagine it as a cube or a box: it has exactly three dimensions — length, width and height. Take the following practical situation: imagine that you need to figure out where the car is in a multi-story parking lot. Then you have to set three numbers, or three coordinates: floor, row and place in a row.
The following code creates the three-dimensional array you just saw above:
val array3D = arrayOf(
arrayOf(arrayOf(0,1), arrayOf(2,3)),
arrayOf(arrayOf(4,5), arrayOf(6,7))
)
println(array3D.contentDeepToString()) // [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
Accordingly, in order to refer to an element of such an array, we need three indices:
println(array3D[0][0][1]) // 1
println(array3D[1][0][1]) // 5
println(array3D[1][1][1]) // 7
You can create arrays of other dimensions by analogy — 4, 5, 6, and so on — as you need. Just remember that an element of a multidimensional array has as many indices as dimensions of that array.
Conclusion
Let's recap. You have figured out what multi-dimensional arrays are and how to create them in Kotlin. Here are the main points to take away:
A multi-dimensional array is essentially an array of arrays.
To find an element of a multi-dimensional array, you need a number of indices equal to the array dimension.
You can explicitly specify a nested array of different types, not only
Int.You can assemble arrays of different types and sizes in a multi-dimensional array.
To print all array elements, you can use the functions
joinToString()andcontentDeepToString().Indexing starts with 0.