- Массивы
- arrayOf()
- Свойство indices
- arrayOfNulls()
- emptyArray()
- val vs var
- Конструктор Array()
- Класс Arrays
- Перебор элементов массива
- Перевернуть массив: reversedArray()
- Перевернуть массив: reverse()
- Сортировка элементов массива
- Содержится ли элемент в массиве
- Найти среднее значение чисел в массиве
- Подсчитать сумму чисел в массиве
- Найти наибольшее и наименьшее число в массиве
- Функция intersect(): найти общие элементы двух массивов
- Выбрать случайную строку из массива
- shuffle(): Перемешать элементы (Kotlin 1.40)
- onEach(): Операция с каждым элементом массива по очереди (Kotlin 1.40)
- Двумерные массивы
- Коллекции. List (Списки)
- listOf()
- Сортировка: sort, sorted, sortedDescending, sortBy, sortByDescending, sortWith
- emptyList()
- listOfNotNull()
- arrayListOf()
- mutableListOf()
- Операции с двумя списками
- replaceAll (Kotlin 1.2)
- fill (Kotlin 1.2)
- joinToString()
- Создать список из случайных чисел
- ArrayDeque (Kotlin 1.3.70)
- Упражнения для коллекций
Массивы
Рассмотрим работу с массивами в Kotlin, которые являются классами.
Массив можно создать двумя способами — через конструктор Array() или через методы arrayOf(), arrayOfNulls(), emptyArray().
arrayOf()
Создадим массив и получим значение третьего элемента.
Узнать длину массива можно при помощи свойства size.
А что случится, если мы добавим в массив строки?
Ничего страшного, у нас получился массив смешанного типа. Всё работает, ничего не ломается.
Если мы хотим строгого поведения и не хотим смешивать разные типы, то используем обобщения.
Существует также синонимы метода, когда уже в имени содержится подсказка: intArrayOf(), harArrayOf(), booleanArrayOf(), longArrayOf(), shortArrayOf(), byteArrayOf().
Пройтись по элементам массива и узнать значение индекса можно с помощью метода withIndex():
Свойство indices
У массива есть свойство indices и мы можем переписать пример по другому.
Свойство возвращает интервал Range, который содержит все индексы массива. Это позволяет не выйти за пределы массива и избежать ошибки ArrayIndexOutOfBoundsException.
Но у свойства есть очень интересная особенность. Взгляните на код:
Из интервала индексов массива мы убрали третий элемент (отсчёт от 0). И теперь при выводе элементов массива мы не увидим числа 3.
Можно сложить два массива.
arrayOfNulls()
Для создания массива с заполненными значениями null можно использовать отдельную функцию arrayOfNulls().
Создадим массив с тремя элементами.
Присвоим значения пустым элементам.
emptyArray()
Создадим пустой массив и заполним его данными.
val vs var
Нужно уяснить разницу между var и val при работе с массивами.
Фактически мы уничтожили первый массив и создали вместо него второй массив.
Если мы попытаем написать такой же код с использованием val, то компилятор запретит такое действие.
Но при этом вы можете менять значения элементов массива, созданного через val.
Конструктор Array()
При использовании конструктора нужно указать размер массива в первом параметре и лямбда-выражение во втором.
Мы задали пять элементов и каждый элемент в цикле умножаем на 2. В итоге получим массив чисел 0, 2, 4, 6, 8.
Создадим массив строк от «A» до «Z»
Лямбда-выражение принимает индекс элемента массива и возвращает значение, которое будет помещено в массив с этим индексом. Значение вычисляется путём сложения индекса с кодом символа и преобразованием результата в строку.
Можно опустить тип массива и написать Array(26), компилятор самостоятельно определит нужный тип.
Есть отдельные классы для каждого примитивного типа — IntArray, ByteArray, CharArray и т.д.
Можно использовать лямбда-выражение.
Класс Arrays
Для вывода значений массива используйте класс Arrays с методом toString(), который вернёт результат в удобном и читаемом виде. Сейчас в Kotlin появилась функция contentToString(), которая является предпочтительным вариантом.
Перебор элементов массива
Обычный перебор через for.
Можно одной строкой через forEach.
Если нужна информация не только о значении элемента, но и его индексе, то используем forEachIndexed.
Перевернуть массив: reversedArray()
Для операции создадим дополнительную переменную для нового массива с перевёрнутыми значениями. Оригинал останется без изменений.
Перевернуть массив: reverse()
Если оригинал массива нам точно не понадобится, то мы можем перевернуть его без создания нового массива.
Сортировка элементов массива
В Kotlin очень просто сортировать элементы.
Вызываем метод sort(). Мы меняем существующий массив, а не создаём новый.
Сортировать можно не весь массив, а только определённый диапазон. Указываем начало и размер диапазона. Допустим, нам нужно отсортировать только первые три элемента из предыдущего примера.
Сортировка в обратном порядке от наибольшего значения к наименьшему.
Если нужно сохранить исходный массив, то вызываем другие функции, которые создадут новый массив.
Для сортировки объектов указываем компаратор и условие сравнения. Например, мы хотим сравнить котов по их возрастам.
Вместо компаратора можно использовать функцию sortBy() с указанием условия. Сравним теперь котов не по возрасту, а по их именам.
Содержится ли элемент в массиве
Если содержится, то возвращает true.
Найти среднее значение чисел в массиве
Используем функцию average(). Возвращается Double.
Подсчитать сумму чисел в массиве
Найти наибольшее и наименьшее число в массиве
В цикле сравниваем каждое число с эталоном, которые вначале принимает значение первого элемента. Если следующее число массива больше эталона, то берём его значение. В итоге после перебора получим наибольшее число в массиве.
Но можно не писать свой код, а вызвать готовые функции min() и max().
Функция intersect(): найти общие элементы двух массивов
Есть два массива с числами. Нужно сравнить их и найти у них общие числа. Поможет нам функция intersect()
Выбрать случайную строку из массива
Имеется массив строк. Сначала вычисляем размер массива. Затем генерируем случайное число в диапазоне от 0 до (почти) 1, которое умножаем на количество элементов в массиве. После этого результат преобразуется в целое число вызовом toInt(). Получается выражение типа 0.811948208873101 * 5 = 4. В Kotlin есть свой класс Random, поэтому случайное число можно получить другим способом.
По этому принципу можно создать игру «Камень, Ножницы, Бумага».
shuffle(): Перемешать элементы (Kotlin 1.40)
Перемешать элементы массива в случайном порядке можно при помощи нового метода shuffle().
onEach(): Операция с каждым элементом массива по очереди (Kotlin 1.40)
В коллекциях мы можем пройтись по всем элементам и что-то с каждым сделать. Теперь такое возможно и с элементами массива. Пройдёмся по всем числам массива, удвоим каждое число и конвертируем в строку.
Двумерные массивы
Часто одного массива недостаточно. В некоторых случаях удобно использовать двумерные массивы. Визуально их легко представить в виде сетки. Типичный пример — зал в кинотеатре. Чтобы найти нужно место в большом зале, нам нужно знать ряд и место.
Двумерный массив — это массив, который содержит другие массивы. Создадим двумерный массив 5х5 и заполним его нулями.
Сейчас в кинотеатре пусто. Первый зритель берёт билет в центре зала.
По такому же принципу строится трёхмерный массив. На этот раз его можно представить не в виде сетки, а в виде куба. В этом случае сетки идут как бы друг за другом, образуя слои.
Источник
Коллекции. List (Списки)
Коллекции в Kotlin используют множество различных интерфейсов: Iterable, Collection, Set, List, MutableIterable, MutableCollection и др.
В Kotlin нет собственных коллекций, только Java-коллекции. Но при этом в Kotlin они обладают более широкими возможностями, используя расширения. Например, вы можете узнать последний элемент списка или найти максимальное значение в коллекции чисел.
Важная особенность — в Kotlin интерфейсы явно разделены на две группы — изменяемые и неизменяемые. Старайтесь всегда использовать неизменяемые коллекции с доступом для чтения. Если вам нужно изменять коллекцию, то тогда выбирайте другой вариант. Здесь не надо путать с var и val. Если вы создадите список для чтения и привяжете его к переменной var, список всё равно нельзя будет изменить после создания.
Для создания различных типов коллекций есть разные функции. После создания узнаем, какой класс соответствует коллекции. Основные приёмы работы с коллекциями показаны у listOf().
У многих функций есть суффиксы To, By, With: associate, associateTo, associateBy, associateByTo, associateWith, associateWithTo.
В некоторых примерах используются объекты класса Cat.
Функции для создания списков. В списках допустимы дубликаты.
listOf()
Неизменяемые списки List создаются через функцию listOf():
Компилятор определяет тип объекта, который должен содержаться в списке, по типам всех значений, переданных при создании. Например, список в нашем примере инициализируется тремя числами, поэтому компилятор создаёт List с типом List . Тип List также можно задать явно:
Если у вас есть изменяемый список, то его можно сконвертировать в список для чтения через toList():
Доступ к отдельному элементу списка можно получить по номеру индекса через квадратные скобки.
Также можно использовать метод get() с указанием номера индекса.
Но у этих способов есть один недостаток — если вы укажете неправильное значение индекса, то получите исключение ArrayIndexOutOfBoundsException. Вы можете избежать проблемы, если будете использовать метод getOrElse() с указанием значения по умолчанию, если выйдете за пределы допустимых значений. В этом случае вам не придётся обрабатывать исключение.
Другой вариант избежать исключения — использовать getOrNull(), который вернёт null при неправильном индексе. Осталось обработать ситуацию.
Размер списка можно узнать через свойство size. Зная размер, можно без опаски пройтись по всем элементам списка.
Пройтись по всем элементам списка можно через for..in.
Функция associate() позволяет получить Map, используя поля класса как ключ и значение. Например, в нашем случае имена станут ключами, а возраст — ассоциированными значениями.
Функция associateTo() — Зададим отображение originalMap, где ключ является строкой, а значением число. Берём список и применяем наше отображение, указывая нужные поля класса (имя и вес).
Умножаем каждый элемент списка на себя при помощи функции map. Функция проходит по каждому элементу, объединяя результаты в новую коллекцию.
Выводим только имена, игнорируя возраст и другие поля класса.
Можно объединить вызовы функций в цепочки. Выводим имена котов, чей возраст больше 5.
Функция flatMap() работает с коллекцией, содержащей коллекции, и возвращает объединённую «плоскую» коллекцию, содержащую все элементы исходных коллекций.
С помощью any и предиката можно узнать, выполняется ли условие хотя бы для одного элемента.
Выражение !any можно заменить на all.
С помощью all и предиката можно узнать, выполняется ли условие для всех элементов.
Выражение !all можно заменить на any.
С помощью none и предиката можно узнать, что ни один из всех элементов не выполняет условие.
count с предикатом позволяет узнать число элементов в списке, которые соответствуют условию.
Не используйте для этой цели цепочку filter.size, так как вы создаёте промежуточную коллекцию, а это накладные расходы. Функция count считает только количество элементов, а не сами элементы.
fold задаёт начальное значение, а потом собирает все значения в списке от первого к последнему.
reduce работает аналогично, только без указания начального значения.
foldRight работает аналогично fold, только значения берутся от последнего к первому.
reduceRight похож на foldRight без указания начального значения.
forEach позволяет пройтись по всем элементам списка.
forEachIndexed работает аналогично, вдобавок мы можем получить индекс позиции и его значение.
max() позволит получить максимальное значение из списка или null при отсутствии элементов. Работает с базовыми типами. Позже в Kotlin 1.4 метод был переименован в maxOrNull().
Функция min() вычисляет минимальное значение из списка или null при отсутствии элементов. Работает с базовыми типами. Позже в Kotlin 1.4 метод был переименован в minOrNull().
maxBy() возвращает первый элемент с наибольшим значением заданной функции или null, если элементов нет. Работает со всеми типами. Аналогичная функция minBy() возвращает первый элемент с наименьшим значением.
Выберем самого старшего кота.
Функция maxWith() позволяет использовать Comparator. Выберем кота с самым длинным именем.
Кота с самым коротким именем можно вычислить через похожую функцию minWith().
В Kotlin 1.4 появилась новая функция, вычисляющая наибольшее или наименьшее число.
Она удобна при работе с классами для выборки одного поля. Вычислим самого молодого котика.
sumBy() подсчитывает сумму всех элементов, после того, как они подверглись изменению.
При работе с числами Double используйте функцию sumByDouble().
В Kotlin 1.4 появилась новая функция sumOf(), позволяющая суммировать элементы разных типов. Сложим возраст (Int) и вес (Double) всех котов.
Также появились minOfWith() и maxOfWith(), работающие с компаратором.
drop() отсекает указанное число элементов. Также есть функции dropWhile, dropLastWhile.
take оставит первые элементы списка. takeLast оставит последние элементы.
takeWhile оставит первые элементы, которые соответствуют условию.
Соответственно, takeLastWhile() оставит последние элементы, соответствующие условию.
Обратите внимание на разницу между takeWhile() и filter() (см. ниже). Первая функция будет отбирать элементы, пока выполняется условие и прервётся, а вторая пройдётся по всему списку до конца.
takeIf() будет выбирать элементы, если выполняется условие (предикат).
Обратная ситуация — выбирать элементы, если не выполняется условие (предикат).
filter вернёт список, который соответствует предикату. Функция может удалять элементы из коллекции, но не может изменять их (используйте map).
filterNot вернёт список, который не соответствует предикату.
filterNotNull вернёт новый список, не содержащий null.
Расширенная версия filterNotNullTo() уберёт все элементы null и добавит оставшиеся элементы в новый список.
contains() позволит убедиться, что нужный элемент присутствует в списке.
Если нужно проверить сразу несколько элементов, то используйте containsAll(), передавая ему список желаемых элементов.
Получить элемент по индексу можно через elementAt(). Также доступны elementAtOrElse, elementAtOrNull.
first() вернёт первый элемент, соответствующий предикату. Если элемент не будет найдет, то получим исключение NoSuchElementException. Похожая функция firstOrNull вернёт null, если элемент не будет найден.
По такому же принципу работают last() и lastOrNull() для последнего элемента.
find похож на first.
indexOf() вернёт индекс элемента. Функции indexOfFirst(), indexOfLast, lastIndexOf() работают с предикатами.
Функция single() вернёт один уникальный элемент из списка. Если элементов, соответствующих условию, будет несколько будет исключение. singleOrNull вместо исключения вернёт null.
Развернуть элементы списка можно через reverse() и reversed().
Сортировка: sort, sorted, sortedDescending, sortBy, sortByDescending, sortWith
Сортировка оригинального списка происходит через sort().
Отсортировать список можно через sorted(). Возвращается новый список, а оригинальный список остаётся без изменений.
В обратном порядке от большого к меньшему можно через sortedDescending(). Возвращается новый список, а оригинальный список остаётся без изменений.
Сортировка по условию. Отсортируем по именам котов при помощи sortBy().
Аналогично в обратном порядке через sortByDescending().
Если элементы содержат null, то можно сортировать при помощи sortWith() в связке с nullFirst().
Обратная задача решается при помощи nullLast.
Можно сортировать, сравнивая несколько полей класса. Порядок важен. Будем сортировать по имени и по возрасту (имена и возраст могут совпадать в списке).
Сортируем по длине имён в порядке возрастания, используя Comparator.
Если в порядке убывания, то поменяем местами аргументы.
Можно сложить два списка. К элементам первого списка будут добавлены элементы второго списка.
Добавить ещё один элемент можно через plus(). Оригинальный список останется без изменений и будет создан новый список.
Функция minus() отнимает указанный элемент.
Функция average() подсчитывает среднее значение всех элементов списка.
Функция slice возвращает список по указанным индексам.
Функция shuffled() создаёт новый список с перемешанными элементами от старого списка.
Функция shuffle() (Kotlin 1.2) перемешивает элементы изменяемого списка в случайном порядке.
Разбить список на отдельные элементы с определённым условием можно через функцию partition. При значении true элементы попадают в одну группу, а остальные в другую. Возвращается объект Pair, содержащий два списка.
Разделим котов на молодых и пожилых.
groupBy группирует значения по некоторому критерию. Например, мы хотим разбить список котов по возрасту.
На выходе получается словарь с ключами (Map >), которые определяют признак группировки (в нашем случае это возраст). Мы получили одну группу котов с возрастом 5 лет и вторую группу с возрастом 9 лет. Вы можете изменить словарь при помощи mapKeys и mapValues.
Список может содержать дубликаты. Но если вы хотите избавиться от них, то можно преобразовать список во множество, а затем снова в список. Существует готовая функция distinct(), которая сделает это за вас.
Можно задать более точный критерий — например, ищем дубликаты по имени или по возрасту через distinctBy().
Можно даже создать сразу несколько условий для поиска дубликатов. Например, поищем дубликаты и по имени и по возрасту. Пусть у нас будет целая орава котов с одинаковыми именами. Некоторые из них могут быть одного возраста. Вес тоже может совпадать, но пока он нас не интересует.
emptyList()
Пустой неизменяемый список можно создать через emptyList(), который вернёт тип List.
listOfNotNull()
Ещё один вид неизменяемых списков — listOfNotNull(). Вы можете поместить в список null, но они будут отсечены.
arrayListOf()
Изменяемый список создаётся через arrayListOf(), который возвращает ArrayList.
Сделаем обход коллекции с использованием индекса.
mutableListOf()
Изменять данные можно только в изменяемых списках. Но если у вас есть в наличии неизменяемый список, то его можно сконвертировать в изменяемый через специальный метод toMutableList(). При этом будет создан новый список.
А можно сразу создать изменяемый список нужного типа через mutableListOf (). Также есть перегруженная версия без указания нужного типа — mutableListOf().
При изменении списков индексы пересчитываются.
Удалить элемент из изменяемого списка можно через removeIf(), указав лямбда-выражение в качестве условия.
Удалить все элементы, которые подчиняются условию, можно также через removeAll():
Если надо не удалить, а оставить элементы по определённому условию, то используйте функцию retainAll().
Операции с двумя списками
С помощью addAll() можно добавить в список элементы другого списка.
Другой способ — функция plusAssign():
Вычитать элементы одного списка при помощи элементов другого списка можно через minusAssign().
Ещё один способ объединения двух списков с сохранением только уникальных элементов через union(). Обратите внимание на порядок сохранения — сначала берутся элементы основного списка, а затем добавляются элементы добавляемого списка.
Функция-комбинатор zip() принимает разные коллекции и объединяют их в одну новую. Для примера объединим два списка: с именами котов и их размерами. Функция zip() возвращает новый список (коллекцию пар Pair). Для этой коллекции пар вызовем функцию toMap(), чтобы получить ассоциативный массив, к элементам которого можно обращаться по ключу. В этом случае ключ — имя кота.
Также можно добавлять элементы в список через операторы + и -. Создадим третий список, используя два списка и отдельные элементы.
Попробуем вычитать элементы из списка.
Допустим и такой вариант.
Интересный случай с использованием += и -=. В этом случае следует использовать var, так как мы изменяем список.
replaceAll (Kotlin 1.2)
Заменяет каждый элемент списка новым значением в результате заданного выражения. Доступно для API 24 и выше
fill (Kotlin 1.2)
Заменяет все элементы списка заданным значением.
Все коллекция являются стандартными и полностью совместимыми с Java, Kotlin не использует собственных коллекций, но тем не менее предлагает удобные методы из коробки. Выше были показаны примеры для списков. Можно применять методы для других коллекций.
Например, найдём последний элемент из коллекции.
joinToString()
Встроенная котлиновская функция для создания строки из элементов коллекции. Вы можете задать собственный префикс и постфикс, а также разделитель. При большом количестве элементов можно задать лимит, тогда будут показаны первые элементы коллекции и после них многоточие.
Функция использует параметры по умолчанию, поэтому часть параметров можно опускать.
Создать список из случайных чисел
В Kotlin можно создать функцию для генерации списка из случайных чисел очень лаконичным способом.
ArrayDeque (Kotlin 1.3.70)
Упражнения для коллекций
Имеется список, некоторые элементы которого повторяются несколько раз. Найти самый повторяемый элемент.
Источник