**Tuples & lists** # Pairs & triples - Kotlin does not have a general $n$-tuple type like Python, but it has pairs (a 2-tuple type) and triples (a 3-tuple type). ```kotlin >>> var p = Pair(2, 3.5) >>> p = Pair(1, 2) error: type inference failed. Expected type mismatch: inferred type is Pair< Int, Int > but Pair< Int, Double > was expected p = Pair(1, 2) ^ >>> p = Pair(1, 2.0) ``` - The components of a pair or triple can be accessed as the properties `first`, `second`, and `third`. ```kotlin >>> p.first 1 >>> p.second 2.0 ``` - Pairs and triples are "generic types", e.g., the type of `Pair(1, 2.0)` is `Pair< Int, Double>`. The "type parameters" are written comma-separated inside angle brackets. Type parameters indicate the components' types. - You can also write `Pair(a, b)` using infix notation as `a to b`. - Kotlin implements pairs and triples as data classes. Thus, they come equipped with a nice `toString()` method, and the `==` and `!=` operators work on them in the expected way, ```kotlin >>> val p1 = Pair(1, 2.3) >>> val p2 = 1 to 2.30 >>> p1 == p2 true >>> p1 != p2 false >>> p1 (1, 2.3) ``` # Destructuring declarations - When declaring variables, you can "destructure" a pair or triple like in Python: ```kotlin >>> var p = Pair(1, 2.0) >>> val (n, d) = p >>> n 1 >>> d 2.0 ``` - The _destructuring declaration_ `val (n, d) = p` declares two variables and give them values at once. It's equivalent to writing ```kotlin >>> val n = p.first >>> val d = p.second ``` - Pairs and triples are useful for returning more than one value from a function, and destructuring allows one to concisely declare multiple variables to capture the return values of a function. # Lists - A `List` is a generic type containing objects of the same type arranged in a linear sequence that can be accessed through a nonnegative index. For any type `T`, `List< T >` is an immutable list of elements of type `T`. - E.g., ```kotlin >>> val students = listOf("Alice", "Bob", "Charlie", "David") >>> students [Alice, Bob, Charlie, David] >>> students.size 4 >>> students[0] Alice >>> students[3] David ``` - The type of `students` is `List< String >`---every list element has type `String`. It contains `students.size` elements that can be indexed as `students[i]` for all indices from `0` to `students.lastIndex`, that is, for any list `L`, `L.lastIndex == students.size - 1` holds. # List iteration - You can iterate over a list using this `for`-loop construct: ```kotlin >>> for (s in students) ... println(s) Alice Bob Charlie David ``` - If you need to know the indices of elements while iterating over the list, you can write ```kotlin >>> for (i in students.indices) ... println("$i: ${students[i]}") 0: Alice 1: Bob 2: Charlie 3: David ``` # List properties and functions I - Some useful properties and functions of every list `L` follow. + `L.size` gives the length of the list; + `L.lastIndex` is the greatest valid index; it equals `L.size-1`; + `L.first()` gives the initial element of the sequence; + `L.last()` gives the final element of the sequence; + `L.isEmpty()` is `true` iff `L.size == 0`; + `L.isNotEmpty()` is `true` iff `L.size != 0`; + `e in L` (or `L contains e`) is `true` iff `L` contains an element equal to `e`; + `L.take(n)` returns a new list containing the first $n$ elements of `L`; + `L.drop(n)` returns a new list containing all elements of `L` except the first $n$; + `L.takeLast(n)` returns a new list containing the last $n$ elements of `L`; + `L.dropLast(n)` returns a new list containing all elements of `L` except the last $n$; # List properties and functions II - More useful functions of every lists `L`, `L1` and `L2` follow. + `L.max()`, `L.min()`, `L.sum()`, and `L.average()` returns the largest, smallest, sum, and average of the elements of the numeric list `L`; + `L.reversed()` returns a new list with elements of `L` in reverse order; + `L.sorted()` and `L.sortedDescending()` returns a new list with elements of `L` in nondecreasing and nonincreasing sorted order; + `L + e` returns a new list containing elements of `L1` with element `e` appended at end; + `L1 + L2` returns a new list containing the concatenation of `L1` and `L2`; + `L.indexOf(e)` and `L.lastIndexOf(e)` return the first and last index whose element is equal to `e`, or -1 if no such index exists; # Mutable lists - A _mutable list_ is a list whose sequence of elements can be modified, i.e., added, removed, or replaced. It can do all that immutable lists can, but it also supports additional functions not supported by immutable lists. - Here are some extra functions callable on mutable lists `m`, `m1`, `m2`: + `m.add(e)` adds element `e` (of the right type) to the end of `m`; + `m.add(i, e)` adds element `e` (of the right type) at index `i` of `m`; + `m1.addAll(m2)` adds all elements of `m2` to the end of `m1`; + `m1.addAll(i, m2)` adds all elements of `m2` at index `i` of `m1`; + `m.remove(e)` removes an element equal to `e` from `m`, if one exists; + `m.removeAt(i)` removes an element at a valid index `i` from `m`; + `m.clear()` removes all elements from `m`; + `m.reverse()` reverses the order of elements in `m`; + `m.sort()` and `m.sortDescending()` sorts the elements of `m` in nondecreasing and nonincreasing order; + `m.shuffle()` rearranges the elements of `m` in a random order; # Example usage of mutable lists - Here is an example usage of mutable lists. ```kotlin >>> val m1 = mutableListOf< String >() >>> m1 [] >>> val m2 = mutableListOf("Alice", "Bob", "Ben", "Charlie") >>> m2 [Alice, Bob, Ben, Charlie] >>> m2.add("Dave") true >>> m2 [Alice, Bob, Ben, Charlie, Dave] >>> m2.removeAt(2) Ben >>> m2 [Alice, Bob, Charlie, Dave] >>> m2.sortDescending() >>> m2 [Dave, Charlie, Bob, Alice] >>> m2.shuffle() >>> m2 [Ben, Alice, Bob, Charlie] ``` _---San Skulrattanakulchai_