Список специфических операций
List — это самый популярный тип встроенного набора в Kotlin. Доступ к элементам списков по индексу предоставляет мощный набор операций для работы со списками.
Получение элементов по индексу
Списки поддерживают все общие операции для получения элементов: elementAt(), first(), last(), и другие, перечисленные в Получение отдельных элементов. Особенностью списков является доступ к элементам по индексу, поэтому самый простой способ прочитать элемент — получить его по индексу. Это делается с помощью функции get() с индексом в качестве аргумента или с использованием сокращённого синтаксиса [index].
Если размер списка меньше указанного индекса, выбрасывается исключение. Существуют две другие функции, которые помогут избежать таких исключений:
-
getOrElse()позволяет указать функцию для вычисления значения по умолчанию, которое будет возвращено, если индекс не присутствует в коллекции. -
getOrNull()возвращаетnullв качестве значения по умолчанию.
fun main() {
//sampleStart
val numbers = listOf(1, 2, 3, 4)
println(numbers.get(0))
println(numbers[0])
//numbers.get(5) // exception!
println(numbers.getOrNull(5)) // null
println(numbers.getOrElse(5, {it})) // 5
//sampleEnd
}
Получение частей списка
Помимо общих операций для Получения частей коллекции, списки предоставляют функцию subList(), которая возвращает представление заданного диапазона элементов в виде списка. Таким образом, если элемент исходной коллекции изменяется, он также изменяется в ранее созданных подсписках и наоборот.
fun main() {
//sampleStart
val numbers = (0..13).toList()
println(numbers.subList(3, 6))
//sampleEnd
}
Поиск позиций элементов
Линейный поиск
В любом списке вы можете найти позицию элемента, используя функции indexOf() и lastIndexOf(). Они возвращают первую и последнюю позиции элемента, равного заданному аргументу в списке. Если таких элементов нет, обе функции возвращают -1.
fun main() {
//sampleStart
val numbers = listOf(1, 2, 3, 4, 2, 5)
println(numbers.indexOf(2))
println(numbers.lastIndexOf(2))
//sampleEnd
}
Также есть пара функций, которые принимают предикат и ищут элементы, соответствующие ему:
-
indexOfFirst()возвращает индекс первого элемента, соответствующего предикату, или-1, если таких элементов нет. -
indexOfLast()возвращает индекс последнего элемента, соответствующего предикату, или-1, если таких элементов нет.
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4)
println(numbers.indexOfFirst { it > 2})
println(numbers.indexOfLast { it % 2 == 1})
//sampleEnd
}
Бинарный поиск в отсортированных списках
Есть еще один способ поиска элементов в списках — бинарный поиск. Он работает значительно быстрее, чем другие встроенные функции поиска, но требует, чтобы список был отсортирован в порядке возрастания по определенному порядку: естественному или другому, заданному в параметре функции. В противном случае результат не определен.
Для поиска элемента в отсортированном списке вызовите функцию binarySearch(), передав значение в качестве аргумента. Если такой элемент существует, функция возвращает его индекс; в противном случае возвращает (-insertionPoint - 1), где insertionPoint — индекс, куда этот элемент должен быть вставлен, чтобы список оставался отсортированным. Если существует более одного элемента с заданным значением, поиск может вернуть любой из их индексов.
Вы также можете указать диапазон индексов для поиска: в этом случае функция ищет только между двумя указанными индексами.
fun main() {
//sampleStart
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println(numbers)
println(numbers.binarySearch("two")) // 3
println(numbers.binarySearch("z")) // -5
println(numbers.binarySearch("two", 0, 2)) // -3
//sampleEnd
}
Бинарный поиск с компаратором
Когда элементы списка не Comparable, вы должны предоставить Comparator для использования в бинарном поиске. Список должен быть отсортирован в порядке возрастания по этому Comparator. Посмотрим на пример:
data class Product(val name: String, val price: Double)
fun main() {
//sampleStart
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch(Product("AppCode", 99.0), compareBy<Product> { it.price }.thenBy { it.name }))
//sampleEnd
}
Вот список Product экземпляров, которые не Comparable, и Comparator определяющий порядок: продукт p1 предшествует продукту p2 если цена p1 меньше цены p2. Таким образом, имея список, отсортированный по возрастанию согласно этому порядку, мы используем binarySearch() для поиска индекса указанного Product.
Пользовательские компараторы также полезны, когда список использует порядок, отличный от естественного, например, регистронезависимый порядок для String элементов.
fun main() {
//sampleStart
val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
println(colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER)) // 3
//sampleEnd
}
Бинарный поиск по сравнению
Бинарный поиск с функцией сравнения позволяет находить элементы без явного указания значений поиска. Вместо этого он принимает функцию сравнения, отображающую элементы в Int значения и ищет элемент, где функция возвращает ноль. Список должен быть отсортирован по возрастанию согласно предоставленной функции; другими словами, возвращаемые значения сравнения должны увеличиваться от одного элемента списка к следующему.
import kotlin.math.sign
//sampleStart
data class Product(val name: String, val price: Double)
fun priceComparison(product: Product, price: Double) = sign(product.price - price).toInt()
fun main() {
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch { priceComparison(it, 99.0) })
}
//sampleEnd
Как поиск с компаратором, так и поиск по сравнению могут выполняться для диапазонов списка.
Операции записи в список
Помимо операций изменения коллекции, описанных в Операциях записи в коллекции, изменяемые списки поддерживают специфические операции записи. Такие операции используют индексы для доступа к элементам, расширяя возможности изменения списка.
Добавление
Чтобы добавить элементы в определённую позицию в списке, используйте add() и addAll(), указав позицию для вставки элемента в качестве дополнительного аргумента. Все элементы, следующие за позицией, смещаются вправо.
fun main() {
//sampleStart
val numbers = mutableListOf("one", "five", "six")
numbers.add(1, "two")
numbers.addAll(2, listOf("three", "four"))
println(numbers)
//sampleEnd
}
Обновление
Списки также предлагают функцию замены элемента в заданной позиции - set() и её операторная форма []. set() не изменяет индексы других элементов.
fun main() {
//sampleStart
val numbers = mutableListOf("one", "five", "three")
numbers[1] = "two"
println(numbers)
//sampleEnd
}
fill() просто заменяет все элементы коллекции указанным значением.
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4)
numbers.fill(3)
println(numbers)
//sampleEnd
}
Удаление
Чтобы удалить элемент в определённой позиции из списка, используйте функцию removeAt(), передав позицию в качестве аргумента. Все индексы элементов, следующих за удаляемым элементом, уменьшатся на единицу.
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.removeAt(1)
println(numbers)
//sampleEnd
}
Для удаления первого и последнего элемента существуют удобные сокращения removeFirst() и removeLast(). Обратите внимание, что для пустых списков они выбрасывают исключение. Чтобы получить null вместо этого, используйте removeFirstOrNull() и removeLastOrNull()
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.removeFirst()
numbers.removeLast()
println(numbers)
val empty = mutableListOf<Int>()
// empty.removeFirst() // NoSuchElementException: List is empty.
empty.removeFirstOrNull() //null
//sampleEnd
}
Сортировка
В Сортировка коллекций мы описываем операции, которые извлекают элементы коллекции в определённом порядке. Для изменяемых списков стандартная библиотека предлагает аналогичные функции расширения, которые выполняют те же операции сортировки на месте. Когда вы применяете такую операцию к экземпляру списка, порядок элементов в этом экземпляре изменяется.
Функции сортировки на месте имеют аналогичные имена функциям, которые применяются к неизменяемым спискам, но без суффикса ed/d.
-
sort*вместоsorted*в именах всех функций сортировки:sort(),sortDescending(),sortBy()и так далее. -
shuffle()вместоshuffled(). -
reverse()вместоreversed().
asReversed() вызываемая для изменяемого списка возвращает другой изменяемый список, который представляет собой обращенную копию исходного списка. Изменения в этом представлении отражаются в исходном списке. Следующий пример демонстрирует функции сортировки для изменяемых списков:
fun main() {
//sampleStart
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println("Sort into ascending: $numbers")
numbers.sortDescending()
println("Sort into descending: $numbers")
numbers.sortBy { it.length }
println("Sort into ascending by length: $numbers")
numbers.sortByDescending { it.last() }
println("Sort into descending by the last letter: $numbers")
numbers.sortWith(compareBy<String> { it.length }.thenBy { it })
println("Sort by Comparator: $numbers")
numbers.shuffle()
println("Shuffle: $numbers")
numbers.reverse()
println("Reverse: $numbers")
//sampleEnd
}
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/list-operations.html