Выбор одного элемента

В Kotlin существует набор функций для извлечения отдельных элементов из коллекции. Функции, описанные в этом разделе, применимы как к спискам, так и к множествам (Set).

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

В свою очередь множество не является упорядоченной коллекцией по определению. Однако в Kotlin Set хранит элементы в определённом порядке. Это может быть порядок вставки (как в LinkedHashSet), естественный порядок сортировки (как в SortedSet) или какой-либо другой порядок. Но также порядок может быть и неизвестен. В таком случае элементы всё равно каким-то образом упорядочены, поэтому функции, которые полагаются на позиции элементов, по-прежнему возвращают свои результаты. Однако такие результаты непредсказуемы для конечного пользователя, если он не знает, какую из реализаций использует Set.

Получение элемента по его позиции

Для получения элемента в определённой позиции существует функция elementAt(). При вызове передайте ей целое число в качестве аргумента и она вернёт вам элемент коллекции, который находится в данной позиции. У первого элемента позиция равна 0, а у последнего - (size - 1).

Функция elementAt() полезна для использования с коллекциями, которые не предоставляют индексированный доступ. При работе с List более идиоматично использовать оператор доступа по индексу (get() или []).

fun main() {
    val numbers = linkedSetOf("one", "two", "three", "four", "five")
    println(numbers.elementAt(3)) // four

    // элементы хранятся в порядке возрастания
    val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
    println(numbersSortedSet.elementAt(0)) // four
}

Также существуют полезные функции для получения первого и последнего элемента коллекции: first() и last().

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.first()) // one
    println(numbers.last()) // five
}

Чтобы избежать исключений при обращении к несуществующим в коллекции элементам, используйте безопасные варианты функции elementAt():

  • elementAtOrNull() - возвращает null, если указанная позиция выходит за границы коллекции.
  • elementAtOrElse() - дополнительно принимает лямбда-функцию. Когда происходит вызов с позицией, которая выходит за границы коллекции, elementAtOrElse() возвращает результат выполнения лямбды.
fun main() {
    val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.elementAtOrNull(5)) // null
    println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"}) // The value for index 5 is undefined
}

Получение элемента по условию

Функции first() и last() позволяют искать в коллекции элементы, соответствующие заданному предикату. При вызове функции first() с предикатом, вы получите первый элемент, для которого предикат возвращает true. В свою очередь функция last() с предикатом вернёт последний элемент, соответствующий предикату.

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.first { it.length > 3 }) // three
    println(numbers.last { it.startsWith("f") }) // five
}

Если ни один элемент не соответствует предикату, обе функции выбросят исключение. Чтобы этого избежать, используйте firstOrNull() и lastOrNull(): эти функции вернут null, если элементы не найдены.

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.firstOrNull { it.length > 6 }) // null
}

Также вы можете использовать нижеперечисленные функции, если их имена лучше подходят для вашей ситуации:

fun main() {
    val numbers = listOf(1, 2, 3, 4)
    println(numbers.find { it % 2 == 0 }) // 2
    println(numbers.findLast { it % 2 == 0 }) // 4
}

Получение элемента с помощью селектора

Если перед извлечением элемента вы хотите его преобразовать, то используйте функцию firstNotNullOf(). Она сочетает в себе два действия:

  • Преобразует коллекцию с помощью функции селектора.
  • Возвращает первое значение, не равное null.

Функция firstNotNullOf() бросает исключение NoSuchElementException, если не было найдено значения, отличного от null. Чтобы этого избежать, используйте функцию firstNotNullOfOrNull(), которая в этом случае вернёт null.

fun main() {
    val list = listOf<Any>(0, "true", false)
    // Преобразует каждый элемент в строку и возвращает первый элемент с нужной длиной.
    val longEnough = list.firstNotNullOf { item -> item.toString().takeIf { it.length >= 4 } }
    println(longEnough) // true
}

Получение случайного элемента

Функция random() позволяет получить произвольный элемент коллекции. Её можно вызывать без аргументов, либо с объектом Random.

fun main() {
    val numbers = listOf(1, 2, 3, 4)
    println(numbers.random()) // 1
}

Если коллекция пуста, то функция random() выбросит исключение. Чтобы вместо исключения получать null, используйте randomOrNull().

Проверка на наличие элемента

Чтобы проверить есть ли в коллекции определённый элемент, используйте функцию contains(). Функция вернёт true, если элемент, переданный ей в качестве аргумента, есть в коллекции. Также эту функцию можно использовать в форме оператора при помощи ключевого слова in.

Для проверки на наличие в коллекции сразу нескольких элементов используйте функцию containsAll(). В качестве аргумента передайте ей коллекцию искомых элементов.

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.contains("four")) // true
    println("zero" in numbers) // false

    println(numbers.containsAll(listOf("four", "two"))) // true
    println(numbers.containsAll(listOf("one", "zero"))) // false
}

Помимо прочего, вы можете проверить, содержит ли коллекция какие-либо элементы, вызвав isEmpty() или isNotEmpty().

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.isEmpty()) // false
    println(numbers.isNotEmpty()) // true

    val empty = emptyList<String>()
    println(empty.isEmpty()) // true
    println(empty.isNotEmpty()) // false
}