Collection
https://kotlinlang.org/docs/collections-overview.html |
https://kotlinlang.org/docs/constructing-collections.html |
Array
Класс для работы с массивами фиксированного размера. Он хранит элементы одного типа и предоставляет индексированный доступ к ним.
val array = arrayOf(1, 2, 3)
array[0] = 10 // Изменение элемента
println(array[0]) // 10
contentToString
Преобразует массив в строку.
// Пример для массива
val numbers = arrayOf(1, 2, 3, 4, 5)
val stringRepresentation = numbers.contentToString()
println(stringRepresentation) // Output: [1, 2, 3, 4, 5]
Iterable
https://kotlinlang.org/docs/iterators.html |
Интерфейс коллекции элементов, которые можно перебрать.
MutableIterable
Интерфейс, расширяющий Iterable
. Позволяет не только перебирать элементы, но и удалять их.
Collection
Неизменяемую коллекцию элементов.
val collection: Collection<Int> = listOf(1, 2, 3)
println(collection.contains(2)) // true
MutableCollection
Расширяет Collection
, добавляя методы для изменения коллекции.
val mutableCollection: MutableCollection<Int> = mutableListOf(1, 2, 3)
mutableCollection.add(4)
mutableCollection.remove(2)
println(mutableCollection) // [1, 3, 4]
List
https://kotlinlang.org/docs/list-operations.html |
Неизменяемый список.
val list = listOf(1, 2, 3)
println(list[0]) // 1
MutableList
Изменяемый список.
val list = mutableListOf(1, 2, 3)
list.add(4)
list[1] = 5
println(list) // [1, 5, 3, 4]
Set
https://kotlinlang.org/docs/set-operations.html |
Неизменяемая коллекция уникальных элементов.
val set = setOf(1, 2, 3, 3)
println(set) // [1, 2, 3]
MutableSet
Изменяемая коллекция уникальных элементов.
val set = mutableSetOf(1, 2, 3)
set.add(4)
println(set) // [1, 2, 3, 4]
Map
https://kotlinlang.org/docs/map-operations.html |
Изменяемый ассоциативный массив.
val map = mapOf("a" to 1, "b" to 2)
println(map["a"]) // 1
MutableMap
Изменяемый ассоциативный массив.
val map: MutableMap<String, Int> = mutableMapOf()
map["one"] = 1 // Добавление
map.put("two", 2) // Альтернативный способ
println(map["one"]) // Выводит: 1
map.remove("one") // Удаление
println(map) // Выводит: {two=2}
Sequences
https://kotlinlang.org/docs/sequences.html |
04.04.2022 | https://www.raywenderlich.com/31290959-kotlin-sequences-getting-started |
Последовательности представляет собой ленивую коллекцию, которая позволяет эффективно работать с большими объемами данных или сложными цепочками преобразований. Основная особенность Sequence — это ленивое выполнение, что означает, что элементы вычисляются по мере необходимости, а не сразу.
• Вычисляет элементы только при необходимости, а не сразу при создании. Это позволяет избежать лишних вычислений и экономит ресурсы. Это особенно полезно при работе с большими данными или при выполнении сложных цепочек преобразований.
• Методы, такие как map
, filter
, и flatMap
возвращают новый Sequence
, который будет вычисляться при итерации. Преобразования применяются по цепочке, что минимизирует количество проходов по данным.
• Sequence предоставляет возможности для работы с данными, которые могут быть получены из различных источников, таких как коллекции, потоки данных и т.д.
// Элементы фильтруются и преобразуются по мере необходимости, а не сразу.
val numbers = (1..10).asSequence()
val result = numbers
.filter { it % 2 == 0 }
.map { it * it }
.toList()
println(result) // Output: [4, 16, 36, 64, 100]
Отличие от коллекций
Основное различие между Sequences и коллекциями в Kotlin заключается в способе обработки данных: ленивое вычисление в последовательностях и жадное вычисление в коллекциях. Sequence более подходит для ленивых вычислений и сложных цепочек преобразований, в то время как коллекции подходят для простых задач с быстрым доступом к данным.
Коллекции:
• Операции, такие как map
, filter
, и другие, выполняются сразу над всеми элементами коллекции.
• При каждом преобразовании (например, при применении нескольких последовательных функций map
, filter
) коллекция обрабатывается целиком на каждом шаге. Это может приводить к нескольким проходам по данным.
• Эффективны для небольших наборов данных или когда нужно быстро получить результат сразу после выполнения всех операций.
• Поддерживают произвольный доступ (например, list[2]
), что делает их удобными для операций, зависящих от индексов.
// Сначала вся коллекция умножается на 2, а затем результат фильтруется, что приводит к двум проходам по данным.
val result = listOf(1, 2, 3, 4, 5)
.map { it * 2 }
.filter { it % 3 == 0 }
.toList()
Последовательности:
• Выполняются лениво, что означает, что операции, такие как map или filter
, откладываются до момента, когда результат действительно нужен (например, когда вызывается терминальная операция вроде toList
).
• Все преобразования выполняются поэтапно для каждого элемента. Например, при цепочке преобразований элемент обрабатывается через все этапы сразу, что может сэкономить ресурсы.
• Более эффективны для работы с большими объемами данных или сложными цепочками операций, так как они не выполняют лишние вычисления и используют память экономнее.
• Работают с последовательными операциями и не поддерживают произвольный доступ, что может сделать их менее удобными для некоторых задач.
// Каждый элемент будет умножен на 2, проверен на делимость на 3 и сохранен в результат, что минимизирует количество операций.
val result = listOf(1, 2, 3, 4, 5)
.asSequence()
.map { it * 2 }
.filter { it % 3 == 0 }
.toList()
asSequence
Преобразует коллекцию в Sequence
.
val list = listOf(1, 2, 3, 4, 5)
val sequence = list.asSequence()
map
Применяет функцию преобразования к каждому элементу.
val transformedSequence = sequence.map { it * 2 }
filter
Отбирает элементы, удовлетворяющие условию.
val filteredSequence = sequence.filter { it % 2 == 0 }
generateSequence
Позволяет создавать бесконечные последовательности, которые можно ограничить с помощью методов, таких как take
.
val infiniteSequence = generateSequence(1) { it + 1 }
val firstFive = infiniteSequence.take(5).toList()
println(firstFive) // Output: [1, 2, 3, 4, 5]
Operators
forEach
Используется для выполнения действия над каждым элементом коллекции.
val numbers = listOf(1, 2, 3, 4)
numbers.forEach { number ->
println(number) // Выведет: 1, 2, 3, 4
}
forEachIndexed
Позволяет итерировать по элементам коллекции с доступом к их индексу.
val fruits = listOf("Apple", "Banana", "Cherry")
fruits.forEachIndexed { index, fruit ->
println("Index $index: $fruit") // Выведет: Index 0: Apple, Index 1: Banana, Index 2: Cherry
}
map
Преобразует элементы коллекции, создавая новую коллекцию.
val doubled = numbers.map { it * 2 } // [2, 4, 6, 8]
filter
Создает новую коллекцию, содержащую только элементы, соответствующие условию.
val evenNumbers = numbers.filter { it % 2 == 0 } // [2, 4]
reduce
Выполняет агрегирующую операцию над элементами коллекции.
val sum = numbers.reduce { acc, number -> acc + number } // 10
fold
Похож на reduce
, но позволяет задать начальное значение.
val sumWithInitial = numbers.fold(0) { acc, number -> acc + number } // 10
flatMap
Применяет преобразование к каждому элементу и объединяет результаты в одну коллекцию.
val nestedList = listOf(listOf(1, 2), listOf(3, 4))
val flatList = nestedList.flatMap { it } // [1, 2, 3, 4]
distinct
Используется для получения уникальных элементов из коллекции. Этот оператор возвращает новую коллекцию, содержащую только неповторяющиеся элементы, сохраняя при этом порядок их появления в исходной коллекции.
val numbers = listOf(1, 2, 2, 3, 4, 4, 5)
val distinctNumbers = numbers.distinct() // [1, 2, 3, 4, 5]
associate
Преобразует элементы коллекции в ключи и значения на основе переданной лямбды.
val list = listOf("apple", "banana", "cherry")
val map = list.associate { it.first() to it.length }
println(map) // {a=5, b=6, c=6}
associateBy
Cоздает мапу, где ключи определяются лямбдой, а значения остаются элементами коллекции.
val list = listOf("apple", "banana", "cherry")
val map = list.associateBy { it.first() }
println(map) // {a=apple, b=banana, c=cherry}
Вопросы на собесе (15)
Collections (10)
- Kакие типы коллекции существуют в Kotlin?
List
MutableList
Set
MutableSet
Map
MutableMap
- Зачем в Kotlin коллекции делятся на mutable и immutable?
Предотвращается изменение данных при передаче, улучшается предсказуемость и потокобезопасность в многопоточном окружении без дополнительных синхронизаций.
- Разница между mutable и immutable коллекциями в Kotlin?
Mutable коллекции позволяют изменять свои элементы, тогда как immutable коллекции не допускают изменений после создания, требуя создания новых экземпляров при модификации.
- Во что Mutable-коллекции Kotlin превращаются в Java?
Mutable-коллекции в Kotlin превращаются в стандартные изменяемые коллекции Java.
•
MutableList
становитсяjava.util.List
.•
MutableSet
превращается вjava.util.Set
.•
MutableMap
становитсяjava.util.Map
.
- Как работает функция map для коллекций в Kotlin?
Применяет функцию
transform
к каждому элементу исходной коллекции и возвращает новую коллекцию.
- Как получить уникальные объекты из списка?
Использовать оператор
distinct()
. Этот метод сохраняет порядок элементов и убирает дубликаты.
- Как написать свою функцию map для коллекции?
Вот так, используя
inline
:inline fun <T, R> List<T>.map(transform: (T) -> R): List<R> { val result = mutableListOf<R>() for (item in this) { result.add(transform(item)) } return result }
- Какой будет тип и что выведется?
var shortChars = listOf("1", "2") var shortNumbers2 = listOf(1, 2) println( shortChars .reversed() .map { it.toInt() } .zip(shortNumbers2) { a, b -> "$a+$b" } )
Тип будет
List
. Вывод:[2+1, 1+2]
.
- Что напечатает println?
val map = mutableMapOf("ZeroKey" to "0") .plus( "FirstKey" to "1", ).apply { this.plus("SecondKey" to "2") } println(map.values)
[0]
- Будет ли работать это код, как исправить?
val moviesYears = mutableListOf( 1999, 2001, 2012, 2014, 2015, 2017 ) for (year in moviesYears) if (year >= 2014) moviesYears.remove(year)
Код не будет работать корректно, так как нельзя изменять коллекцию (
moviesYears
) во время её итерации — это может привести к пропуску элементов. Исправить можно, используяremoveIf
.
- Kакие типы коллекции существуют в Kotlin?
Sequences (5)
- Для чего нужен Sequence?
Для ленивой обработки коллекций, когда операции применяются к элементам по мере их запроса, что позволяет экономить память и избегать лишних вычислений, особенно с большими наборами данных.
- Как Sequence работает с точки зрения памяти?
Sequence
использует меньше памяти в хипе, так как обрабатывает элементы лениво, создавая их только по мере необходимости и не загружая всю коллекцию в память сразу. Каждый вызов последовательной операции надSequence
создаёт объект, который ссылается на следующий элемент, освобождая память по мере завершения обработки текущих элементов.
- Разница между Collection и Sequences?
Коллекции выполняют все операции сразу, сохраняя промежуточные результаты в памяти, тогда как последовательности обрабатывают элементы лениво, только по мере необходимости, что позволяет работать с большими наборами данных более эффективно.
- В каких случаях Sequence лучше Collections?
Sequence
лучше подходит, когда нужно обработать большие наборы данных или выполнить несколько операций последовательно, избегая создания промежуточных коллекций. Она вычисляется лениво, что помогает сэкономить память и ускорить выполнение в таких случаях.
- Как будут выполняться эти операторы? Как улучшить метод чтобы было меньше накладных расходов?
fun foo3(items: MutableList<Item>) { return items .filterIsInstance<ShiftInterval>() .filter { it.isChecked } .groupBy(...) .mapKeys { ... } .flatMap { ... } }
Операторы будут выполняться последовательно, каждый создавая промежуточные коллекции. Чтобы уменьшить накладные расходы, можно заменить последовательность операций на ленивую обработку с использованием последовательностей (
Sequence
), что позволит избежать создания промежуточных коллекций. Использованиеitems.asSequence()
делает операции ленивыми и уменьшает накладные расходы, так как коллекции не будут создаваться на каждом этапе.
- Для чего нужен Sequence?