From 569bd3ba95a388e659b26bd01818f67b1f284dc4 Mon Sep 17 00:00:00 2001 From: Sarah Haggarty Date: Mon, 17 Oct 2022 17:44:53 +0200 Subject: [PATCH] update: update arrays page --- docs/topics/arrays.md | 388 +++++++++++++++++++++++++--- docs/topics/collections-overview.md | 39 ++- docs/topics/equality.md | 8 +- 3 files changed, 396 insertions(+), 39 deletions(-) diff --git a/docs/topics/arrays.md b/docs/topics/arrays.md index 03084a805a3..88e289637b9 100644 --- a/docs/topics/arrays.md +++ b/docs/topics/arrays.md @@ -1,62 +1,384 @@ [//]: # (title: Arrays) -Arrays in Kotlin are represented by the `Array` class. It has `get()` and `set()` functions that turn into `[]` by operator overloading conventions, -and the `size` property, along with other useful member functions: +An array is a data structure that holds a fixed number of values of the same type or its subtypes. +The most common type of array in Kotlin is the object-type array, represented by the [`Array`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/) class. + +> If you use primitives in an object-type array, this has a performance impact because your primitives are [boxed](https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html) +> into objects. To avoid boxing overhead, use [primitive-type arrays](#primitive-type-arrays) instead. +> +{type="note"} + +## When to use arrays + +Use arrays in Kotlin when you have specialized low-level requirements that you need to meet. For example, if you have +performance requirements beyond what is needed for regular applications, or you need to build custom data structures. If +you don't have these sorts of restrictions, use [collections](collections-overview.md) instead. + +Collections have the following benefits compared to arrays: +* Collections can be read-only, which gives you more control and allows you to write robust code that has a clear intent. +* It is easy to add or remove elements from collections. In comparison, arrays are fixed in size. The only way to +add or remove elements from an array is to create a new array each time, which is very inefficient: + + ```kotlin + fun main() { + //sampleStart + var riversArray = arrayOf("Nile", "Amazon", "Yangtze") + + // Using the += assignment operation creates a new riversArray, + // copies over the original elements and adds "Mississippi" + riversArray += "Mississippi" + println(riversArray.joinToString()) + // Nile, Amazon, Yangtze, Mississippi + //sampleEnd + } + ``` + {kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-rivers-array-kotlin"} + +* You can use the equality operator (`==`) to check if collections are structurally equal. You can't use this operator +for arrays. Instead, you have to use a special function, which you can read more about in [Compare arrays](#compare-arrays). + +For more information about collections, see [Collections overview](collections-overview.md). + +## Create arrays + +To create arrays in Kotlin, you can use: +* functions, such as [`arrayOf()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of.html), [`arrayOfNulls()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of-nulls.html#kotlin$arrayOfNulls(kotlin.Int)) +or [`emptyArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/empty-array.html). +* the `Array` constructor. + +This example uses the [`arrayOf()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of.html) function +and passes item values to it: ```kotlin -class Array private constructor() { - val size: Int - operator fun get(index: Int): T - operator fun set(index: Int, value: T): Unit +fun main() { +//sampleStart + // Creates an array with values [1, 2, 3] + val simpleArray = arrayOf(1, 2, 3) + println(simpleArray.joinToString()) + // 1, 2, 3 +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-simple-array-kotlin"} - operator fun iterator(): Iterator - // ... +This example uses the [`arrayOfNulls()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of-nulls.html#kotlin$arrayOfNulls(kotlin.Int)) +function to create an array of a given size filled with `null` elements: + +```kotlin +fun main() { +//sampleStart + // Creates an array with values [null, null, null] + val nullArray: Array = arrayOfNulls(3) + println(nullArray.joinToString()) + // null, null, null +//sampleEnd } ``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-null-array-kotlin"} + +This example uses the [`emptyArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/empty-array.html) function to +create an empty array : + +```kotlin + var exampleArray = emptyArray() +``` -To create an array, use the function `arrayOf()` and pass the item values to it, so that `arrayOf(1, 2, 3)` creates an array `[1, 2, 3]`. -Alternatively, the `arrayOfNulls()` function can be used to create an array of a given size filled with `null` elements. +> You can specify the type of the empty array on the left-hand or right-hand side of the assignment due to Kotlin's type +> inference. +> +> For example: +> ```Kotlin +> var exampleArray = emptyArray() +> +> var exampleArray: Array = emptyArray() +>``` +> +{type="note"} -Another option is to use the `Array` constructor that takes the array size and the function that returns values -of array elements given its index: +The `Array` constructor takes the array size and a function that returns values for array elements given its index: ```kotlin fun main() { //sampleStart + // Creates an Array that initializes with zeros [0, 0, 0] + val initArray = Array(3) { 0 } + println(initArray.joinToString()) + // 0, 0, 0 + // Creates an Array with values ["0", "1", "4", "9", "16"] val asc = Array(5) { i -> (i * i).toString() } - asc.forEach { println(it) } + asc.forEach { print(it) } + // 014916 +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-array-constructor-kotlin"} + +> Like in most programming languages, indices start from 0 in Kotlin. +> +{type="note"} + +### Nested arrays + +Arrays can be nested within each other to create multidimensional arrays: + +```kotlin +fun main() { +//sampleStart + // Creates a two-dimensional array + val twoDArray = Array(2) { Array(2) { 0 } } + println(twoDArray.contentDeepToString()) + // [[0, 0], [0, 0]] + + // Creates a three-dimensional array + val threeDArray = Array(3) { Array(3) { Array(3) { 0 } } } + println(threeDArray.contentDeepToString()) + // [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]] +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-multidimensional-array-kotlin"} + +> Nested arrays don't have to be the same type or the same size. +> +{type="note"} + +## Access and modify elements + +Arrays are always mutable. To access and modify elements in an array, use the [indexed access operator](operator-overloading.md#indexed-access-operator)`[]`: + +```kotlin +fun main() { +//sampleStart + val simpleArray = arrayOf(1, 2, 3) + val twoDArray = Array(2) { Array(2) { 0 } } + + // Accesses the element and modifies it + simpleArray[0] = 10 + twoDArray[0][0] = 2 + + // Prints the modified element + println(simpleArray[0].toString()) // 10 + println(twoDArray[0][0].toString()) // 2 +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-access-array-kotlin"} + +Arrays in Kotlin are _invariant_. This means that Kotlin doesn't allow you to assign an `Array` +to an `Array` to prevent a possible runtime failure. Instead, you can use `Array`. For more information, +see [Type Projections](generics.md#type-projections). + +## Work with arrays + +In Kotlin, you can work with arrays by using them to pass a variable number of arguments to a function or perform operations +on the arrays themselves. For example, comparing arrays, transforming their contents or converting them to collections. + +### Pass variable number of arguments to a function + +In Kotlin, you can pass a variable number of arguments to a function via the [`vararg`](functions.md#variable-number-of-arguments-varargs) +parameter. This is useful when you don't know the number of arguments in advance, like when formatting a message or +creating an SQL query. + +To pass an array containing a variable number of arguments to a function, use the _spread_ operator +(`*`). The spread operator passes each element of the array as individual arguments to your chosen function: + +```kotlin +fun main() { + val lettersArray = arrayOf("c", "d") + printAllStrings("a", "b", *lettersArray) + // abcd +} + +fun printAllStrings(vararg strings: String) { + for (string in strings) { + print(string) + } +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-vararg-array-kotlin"} + +For more information, see [Variable number of arguments (varargs)](functions.md#variable-number-of-arguments-varargs). + +### Compare arrays + +To compare whether two arrays have the same elements in the same order, use the [`.contentEquals()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-equals.html) +and [`.contentDeepEquals()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-deep-equals.html) +functions: + +```kotlin +fun main() { +//sampleStart + val simpleArray = arrayOf(1, 2, 3) + val anotherArray = arrayOf(1, 2, 3) + + // Compares contents of arrays + println(simpleArray.contentEquals(anotherArray)) + // true + + // Using infix notation, compares contents of arrays after an element + // is changed + simpleArray[0] = 10 + println(simpleArray contentEquals anotherArray) + // false +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-compare-array-kotlin"} + +> Don't use equality (`==`) and inequality (`!=`) [operators](equality.md#structural-equality) to compare the contents +> of arrays. These operators check whether the assigned variables point to the same object. +> +> To learn more about why arrays in Kotlin behave this way, see our [blog post](https://blog.jetbrains.com/kotlin/2015/09/feedback-request-limitations-on-data-classes/#Appendix.Comparingarrays). +> +{type="warning"} + +### Transform arrays + +Kotlin has many useful functions to transform arrays. This document highlights a few but this isn't an +exhaustive list. For the full list of functions, see our [API reference](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/). + +#### Sum + +To return the sum of all elements in an array, use the [`.sum()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sum.html) +function: + +```Kotlin +fun main() { +//sampleStart + val sumArray = arrayOf(1, 2, 3) + + // Sums array elements + println(sumArray.sum()) + // 6 //sampleEnd } ``` -{kotlin-runnable="true" kotlin-min-compiler-version="1.3"} +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-sum-array-kotlin"} + +> The `.sum()` function can only be used with arrays of [numeric data types](numbers.md), such as `Int`. +> +{type="note"} -The `[]` operation stands for calls to member functions `get()` and `set()`. +#### Shuffle -Arrays in Kotlin are _invariant_. This means that Kotlin does not let us assign an `Array` -to an `Array`, which prevents a possible runtime failure (but you can use `Array`, -see [Type Projections](generics.md#type-projections)). +To randomly shuffle the elements in an array, use the [`.shuffle()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/shuffle.html) +function: + +```Kotlin +fun main() { +//sampleStart + val simpleArray = arrayOf(1, 2, 3) + + // Shuffles elements [3, 2, 1] + simpleArray.shuffle() + println(simpleArray.joinToString()) + + // Shuffles elements again [2, 3, 1] + simpleArray.shuffle() + println(simpleArray.joinToString()) +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-shuffle-array-kotlin"} -## Primitive type arrays +### Convert arrays to collections -Kotlin also has classes that represent arrays of primitive types without boxing overhead: `ByteArray`, -`ShortArray`, `IntArray`, and so on. These classes have no inheritance relation to the `Array` class, but they -have the same set of methods and properties. Each of them also has a corresponding factory function: +If you work with different APIs where some use arrays and some use collections, then you can convert your arrays to [collections](collections-overview.md) +and vice versa. + +#### Convert to List or Set + +To convert an array to a `List` or `Set`, use the [`.toList()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-list.html) +and [`.toSet()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-set.html) functions. ```kotlin -val x: IntArray = intArrayOf(1, 2, 3) -x[0] = x[1] + x[2] +fun main() { +//sampleStart + val simpleArray = arrayOf("a", "b", "c", "c") + + // Converts to a Set + println(simpleArray.toSet()) + // [a, b, c] + + // Converts to a List + println(simpleArray.toList()) + // [a, b, c, c] +//sampleEnd +} ``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-convert-list-set-kotlin"} + +#### Convert to Map + +To convert an array to a `map`, use the [`.toMap()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html) +function. + +Only an array of [`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/) can be converted to a `map`. +The first value of a `Pair` instance becomes a key, and the second becomes a value. This example uses the [infix notation](functions.md#infix-notation) +to call the [`to`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html) function to create tuples of `Pair`: ```kotlin -// Array of int of size 5 with values [0, 0, 0, 0, 0] -val arr = IntArray(5) +fun main() { +//sampleStart + val pairArray = arrayOf("apple" to 120, "banana" to 150, "cherry" to 90, "apple" to 140) + + // Converts to a Map + // The keys are fruits and the values are their number of calories + // Note how keys must be unique, so the latest value of "apple" + // overwrites the first + println(pairArray.toMap()) + // {apple=140, banana=150, cherry=90} + +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-convert-map-kotlin"} + +## Primitive-type arrays + +If you use the `Array` class with primitive values, these values are boxed into objects. +As an alternative, you can use primitive-type arrays, which allow you to store primitives in an array without the +side effect of boxing overhead: + +| Primitive-type array | Equivalent in Java | +|---|----------------| +| [`BooleanArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean-array/) | `boolean[]`| +| [`ByteArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte-array/) | `byte[]`| +| [`CharArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char-array/) | `char[]`| +| [`DoubleArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double-array/) | `double[]`| +| [`FloatArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float-array/) | `float[]`| +| [`IntArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int-array/) | `int[]`| +| [`LongArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long-array/) | `long[]`| +| [`ShortArray`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-short-array/) | `short[]`| + +These classes have no inheritance relation to the `Array` class, but they have the same set of functions and properties. + +This example creates an instance of the `IntArray` class: + +```kotlin +fun main() { +//sampleStart + // Creates an array of Int of size 5 with values + val exampleArray = IntArray(5) + println(exampleArray.joinToString()) + // 0, 0, 0, 0, 0 +//sampleEnd +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="arrays-primitive-type-array-kotlin"} + +> To convert primitive-type arrays to object-type arrays, use the [`.toTypedArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-typed-array.html) +> function. +> +> To convert object-type arrays to primitive-type arrays, use [`.toBooleanArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-boolean-array.html), +> [`.toByteArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-byte-array.html), [`.toCharArray()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-char-array.html), +> and so on. +> +{type="note"} -// Example of initializing the values in the array with a constant -// Array of int of size 5 with values [42, 42, 42, 42, 42] -val arr = IntArray(5) { 42 } +## What's next? -// Example of initializing the values in the array using a lambda -// Array of int of size 5 with values [0, 1, 2, 3, 4] (values initialized to their index value) -var arr = IntArray(5) { it * 1 } -``` \ No newline at end of file +* To learn more about why we recommend using collections for most use cases, read our [Collections overview](collections-overview.md). +* Learn about other [basic types](basic-types.md). +* If you are a Java developer, read our Java to Kotlin migration guide for [Collections](java-to-kotlin-collections-guide.md). diff --git a/docs/topics/collections-overview.md b/docs/topics/collections-overview.md index 30b3e324f70..81aba4b07de 100644 --- a/docs/topics/collections-overview.md +++ b/docs/topics/collections-overview.md @@ -6,9 +6,9 @@ of items (possibly zero) that are significant to the problem being solved and ar Collections are a common concept for most programming languages, so if you're familiar with, for example, Java or Python collections, you can skip this introduction and proceed to the detailed sections. -A collection usually contains a number of objects (this number may also be zero) of the same type. Objects in a collection +A collection usually contains a number of objects of the same type (and its subtypes). Objects in a collection are called _elements_ or _items_. For example, all the students in a department form a collection that can be used to -calculate their average age. +calculate their average age. The following collection types are relevant for Kotlin: @@ -30,6 +30,10 @@ collections of any type. The collection interfaces and related functions are located in the `kotlin.collections` package. Let's get an overview of its contents. +> Arrays are not a type of collection. For more information, see [Arrays](arrays.md). +> +{type="note"} + ## Collection types The Kotlin Standard Library provides implementations for basic collection types: sets, lists, and maps. @@ -39,9 +43,11 @@ A pair of interfaces represent each collection type: * A _mutable_ interface that extends the corresponding read-only interface with write operations: adding, removing, and updating its elements. -Note that altering a mutable collection doesn't require it to be a [`var`](basic-syntax.md#variables): write operations -modify the same mutable collection object, so the reference doesn't change. -Although, if you try to reassign a `val` collection, you'll get a compilation error. +Note that a mutable collection doesn't have to be assigned to a [`var`](basic-syntax.md#variables). Write operations with +a mutable collection are still possible even if it is assigned to a `val`. The benefit of assigning mutable collections to +`val` is that you protect the reference to the mutable collection from modification. Over time, as your code grows and becomes +more complex, it becomes even more important to prevent unintentional modification to references. Use `val` as much as possible +for safer and more robust code. If you try to reassign a `val` collection, you get a compilation error: ```kotlin fun main() { @@ -287,3 +293,26 @@ The default implementation of `MutableMap` – [`LinkedHashMap`](https://kotlinl preserves the order of elements insertion when iterating the map. In turn, an alternative implementation – [`HashMap`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-map/index.html) – says nothing about the elements order. + +### ArrayDeque + +[`ArrayDeque`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-array-deque/) is an implementation of a double-ended queue, which allows you to add or remove elements both at the beginning or end of the queue. +As such, `ArrayDeque` also fills the role of both a Stack and Queue data structure in Kotlin. Behind the scenes, `ArrayDeque` is realized using a resizable array that automatically adjusts in size when required: + +```kotlin +fun main() { + val deque = ArrayDeque(listOf(1, 2, 3)) + + deque.addFirst(0) + deque.addLast(4) + println(deque) // [0, 1, 2, 3, 4] + + println(deque.first()) // 0 + println(deque.last()) // 4 + + deque.removeFirst() + deque.removeLast() + println(deque) // [1, 2, 3] +} +``` +{kotlin-runnable="true" kotlin-min-compiler-version="1.4"} \ No newline at end of file diff --git a/docs/topics/equality.md b/docs/topics/equality.md index 46f33aaf699..d95700b2d2b 100644 --- a/docs/topics/equality.md +++ b/docs/topics/equality.md @@ -41,4 +41,10 @@ When an equality check operands are statically known to be `Float` or `Double` ( Otherwise, structural equality is used, which disagrees with the standard so that `NaN` is equal to itself, `NaN` is considered greater than any other element, including `POSITIVE_INFINITY`, and `-0.0` is not equal to `0.0`. -See: [Floating-point numbers comparison](numbers.md#floating-point-numbers-comparison). +For more information, see [Floating-point numbers comparison](numbers.md#floating-point-numbers-comparison). + +## Array equality + +To compare whether two arrays have the same elements in the same order, use [`contentEquals()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-equals.html). + +For more information, see [Compare arrays](arrays.md#compare-arrays). \ No newline at end of file