Массивы

Последнее обновление: 04.03.2024

Массивы во многом аналогичны коллекциям. Массивы характеризуются постоянной длиной, соответственно мы не можем динамически добавлять или удалять элементы из массива. Но мы можем изменять значение уже имеющихся элементов.

Многие общие для коллекций стандартные методы реализованы для класса Array в виде функцирасширения.

Массивы представляют тип Array, который является обобщенным. Например, определим пару массивов:

val numbers: Array<Int>       // массив чисел
val people: Array<String>     // массив строк

Для создания массива применяется функция arrayOf():

val numbers = arrayOf(1, 2, 3, 4, 5)     // объект Array<Int>
val people = arrayOf("Tom", "Sam", "Kate", "Bob", "Alice")   // объект Array<String>

В этом случае тип элементов массива будет выводиться из типа значений из функции arrayOf()

Встроенная функция arrayOfNulls() позволяет создать массив из элементов, каждый из который имеет значение null - то есть фактически не установленное значение. В эту функцию передается количество элементов:

val numbers = arrayOfNulls<Int>(3)  // [null, null, null]

После названия функции в угловых скобках указывается тип элементов массива. Так, в примере выше это тип Int. В данном случае создается массив из трех элементов, каждый из которых равен по умолчанию null, то есть не имеет никакого значения.

Также имеется еще один способ создать массив и инициализировать его значениями:

val numbers = Array(3, {5})	// [5, 5, 5]

Здесь применяется конструктор класса Array. В этот конструктор передаются два значения. Первое значение - число 3 - указывает, сколько элементов будет в массиве. В данном случае 3 элемента. Второе значение - число 5 представляет выражение, которое генерирует элементы массива. Оно заключается в фигурные скобки. В данном случае в фигурных скобках стоит число 5, то есть все элементы массива будут представлять число 5. Таким образом, массив будет состоять из трех пятерок.

Но выражение, которое создает элементы массива, может быть и более сложным. Например:

var i = 1;
val numbers = Array(3, { i++ * 2}) // [2, 4, 6]

В данном случае элемент массива является результатом умножения переменной i на 2. При этом при каждом обращении к переменой i ее значение увеличивается на единицу.

Обращение к элементам массива

Получение данных

Для получения элемента по индексу можно применять метод get(index), который возвращает элемент по индексу

val people = arrayOf("Tom", "Sam", "Kate", "Bob", "Alice")
val first = people.get(0)
val second = people.get(1)
println(first)      // Tom
println(second)     // Sam

Вместо метода get для обращения по индексу можно использовать квадратные скобки []:

val people = arrayOf("Tom", "Sam", "Kate", "Bob", "Alice")
val first = people[0]
val second = people[1]
println(first)      // Tom
println(second)     // Sam

Однако, если индекс выходит за границы списка, то при использовании метода get() и квадратных скобок генерируется исключение. Чтобы избежать подобной ситуации, можно применять метод getOrNull(), который возвращает null, если индекс находится вне границ списка:

val people = arrayOf("Tom", "Sam", "Kate", "Bob", "Alice")
val first = people.getOrNull(0)
val tenth = people.getOrNull(10)
println(first)      // Tom
println(tenth)     // null

Либо в качестве альтернативы можно применять метод getOrElse():

getOrElse(index: Int, defaultValue: (Int) -> T): T

Первый параметр представляет индекс, а второй параметр - функция, которая получает запрошенный индекс и возвращает значение, которое возвращается, если индекс выходит за границы списка:

val people = arrayOf("Tom", "Sam", "Kate", "Bob", "Alice")
val first = people.getOrElse(0){"Undefined"}
val seventh = people.getOrElse(7){"Invalid index $it"}
val tenth = people.getOrElse(10){"Undefined"}
    
println(first)      // Tom
println(seventh)    // Invalid index 7
println(tenth)     // Undefined

Также подобный метод может быть полезен, если массив изначально создан с помощью функции arrayOfNulls и может содержать null, и мы хотим в этом случае возвратить некоторое значение по умолчанию

fun main() {

    val people = arrayOfNulls<String>(3)  // [null, null, null]
    people[0] = "Tom"
    people[1] = "Bob"
    val first = people.getOrElse(0){"Undefined"}
    val last = people.getOrElse(2){"Undefined"}

    println(first)      // Tom
    println(last)     // Undefined
}

Установка данных

Для установки значений элементов можно применять метод set(index, value), который принимает индекс элемента и новое значение, или просто индексы:

val people = arrayOf("Tom", "Bob", "Sam")
people.set(0, "Tomas")
people[1] = "Robert"
println(people[0])  // "Tomas"
println(people[1])  // "Robert"

Свойства массива

Для работы с массивами класс Array предоставляет три свойства:

  • size: размер массива

  • lastIndex: индекс последнего элемента массива, тоже самое, что и size - 1

  • indices: диапазон индексов элементов массива

Каждый массив имеет свойство size, которое хранит количество элементов массива:

val people = arrayOf("Tom", "Bob", "Sam")
println(people.size)  // 3
println(people.lastIndex)  // 2
println(people.indices)     // 0..2

Перебор массивов

Для перебора массивов можно применять цикл for:

fun main() {

    val numbers = arrayOf(1, 2, 3, 4, 5)
    for(number in numbers){
        print("$number \t")
    }
}

В данном случае переменная numbers представляет массив чисел. При переборе этого массива в цикле каждый его элемент оказывается в переменной number, значение которой, к примеру, можно вывести на консоль. Консольный вывод программы:

1  2  3  4  5

Подобным образом можно перебирать массивы и других типов:

fun main() {

    val people = arrayOf("Tom", "Sam", "Bob")
    for(person in people){
        print("$person \t")
    }
}

Консольный вывод программы:

Tom   Sam   Bob

Также при переборе мы можем использовать индексы для обращения к элементам массива:

fun main(){
    val people = arrayOf("Tom", "Sam", "Bob")
    for(i in 0..people.lastIndex){
        println("${i+1} - ${people[i]}")
    }
}

В данном случае мы перебираем не сам массив people, а последовательность чисел от 0 до people.lastIndex, то есть фактически от 0 до 2. Каждое число из этой последовательности попадает в переменную i. Затем получаем каждый элемент массива с помощью выражения people[i]

Может показаться, что последний способ перебора избыточен - мы же напрямую можем перебрать массив, использовав выражение for(person in people). Однако что, если мы хотим изменить все элементы массива. Например, следующим образом:

val numbers = arrayOf(2, 3, 4)
for(n in numbers){
    n = n * n       // так нельзя изменить
}

В данном случае мы хотим, чтобы в массиве каждое число было заменено квадратом этого числа. Однако написать, как в примере выше мы не можем.

Теперь изменим подход:

fun main(){
    val numbers = arrayOf(2, 3, 4)
    // заменяем число в массиве его квадратом
    for(i in 0..numbers.lastIndex){
        numbers[i] = numbers[i] * numbers[i]
    }

    // проверяем массив
    for(n in numbers){
        print("$n \t")
    }
}

Консольный вывод программы:

4 	9 	16 	

Для упрощения перебора индексов элементов массива каждый массив предоставляет свойство indices, который представляет последовательность всех индексов начиная с 0 и которое мы также можем перебрать:

for (i in people.indices) {
	println(people[i])
}

val numbers = arrayOf(2, 3, 4)
for(i in numbers.indices){
    numbers[i] = numbers[i] * numbers[i]
    print("${numbers[i]} \t")
}

Можно применять и другие типы циклов для перебора массива. Например, используем цикл while:

fun main() {

    val people = arrayOf("Tom", "Sam", "Bob")
    
    var i = 0
    while( i in people.indices){
        println(people[i])
        i++;
    }
}

Также для перебора можно использовать функцию расширения forEach(). Она принимает функцию-коллбек, параметр которой представляет каждый элемент массива:

fun main() {

    val people = arrayOf("Tom", "Bob", "Sam")
    people.forEach { p->println(p) }
}

Для перебора вместе с индексами можно использовать функцию forEachIndexed(). Она принимает функцию с двумя параметрами: индексом элемента и самим элементом:

fun main() {

    val people = arrayOf("Tom", "Bob", "Sam")
    people.forEachIndexed { i, p->println("$i. $p") }
}

Консольный вывод:

0. Tom
1. Bob
2. Sam

Двухмерные массивы

Выше рассматривались одномерные массивы, которые можно представить в виде ряда или строки значений. Но кроме того, мы можем использовать многомерные массивы. К примеру, возьмем двухмерный массив - то есть такой массив, каждый элемент которого в свою очередь сам является массивом. Двухмерный массив еще можно представить в виде таблицы, где каждая строка - это отдельный массив, а ячейки строки - это элементы вложенного массива.

Определение двухмерных массивов менее интуитивно понятно и может вызывать сложности. Например, двухмерный массив чисел:

val table: Array<Array<Int>> = Array(3, { Array(5, {0}) })

В данном случае двухмерный массив будет иметь три элемента - три строки. Каждая строка будет иметь по пять элементов, каждый из которых равен 0.

Используя индексы, можно обращаться к подмассивам в подобном массиве, в том числе переустанавливать их значения:

val table = Array(3, { Array(3, {0}) })
table[0] = arrayOf(1, 2, 3)		// первая строка таблицы
table[1] = arrayOf(4, 5, 6)		// вторая строка таблицы
table[2] = arrayOf(7, 8, 9)		// третья строка таблицы

Для обращения к элементам подмассивов двухмерного массива необходимы два индекса. По первому индексу идет получение строки, а по второму индексу - столбца в рамках этой строки:

val table = Array(3, { Array(3, {0}) })
table[0][1] = 6  // второй элемент первой строки
val n = table[0][1]		// n = 6

Используя два цикла, можно перебирать двухмерные массивы:

fun main() {

    val table: Array<Array<Int>> = Array(3, { Array(3, {0}) })
    table[0] = arrayOf(1, 2, 3)
    table[1] = arrayOf(4, 5, 6)
    table[2] = arrayOf(7, 8, 9)
    for(row in table){

        for(cell in row){
            print("$cell \t")
        }
        println()
    }
}

С помощью внешнего цикла for(row in table) пробегаемся по всем элементам двухмерного массива, то есть по строкам таблицы. Каждый из элементов двухмерного массива сам представляет массив, поэтому мы можем пробежаться по этому массиву и получить из него непосредственно те значения, которые в нем хранятся. В итоге на консоль будет выведено следующее:

1 	2 	3 	
4 	5 	6 	
7 	8 	9
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850