Привет, Хабр! Меня зовут Леонид Иванькин, я ведущий Android-разработчик в МТС Digital, работаю над приложением Мой МТС. В этой статье – сложные и не очень задачи, чтобы проверить, насколько хорошо вы разбираетесь в операторах для списков. Готовы испытать свои скиллы? Тогда переходите под кат!
При разработке на Kotlin часто приходится использовать списки (List, MutableList и другие), а также операторы для них. Каждый раз, заходя в документацию, я убеждаюсь, что операторов очень много, а в их использовании есть тонкости.
Многие коллеги говорят, что в этой теме они разбираются на 100%. Давайте проверим, насколько хорошо вы владеете операторами для списков. Я подготовил 14 логических задач разной сложности, попробуйте их решить.
Ставлю на то, что даже опытные разработчики справятся не со всеми задачами, несмотря на кажущуюся простоту :)
Правила
Есть задание — лист элементов. Ваша задача вставить один оператор, чтобы получилось значение в комментариях, которое стоит после знака =. В данной задаче это 1.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.let { println(it) }//=1
Решение здесь тривиальное: нужно взять первый элемент, чтобы получить 1. Применив, например, оператор first().
listOf(1, 3, 3, 2, 4, 1)
.first()
.let { println(it) }//=1
Надеюсь, что правила понятны.
Замечания и допущения
Хочу отметить, что из-за разнообразия операторов и по стечению обстоятельств решений может быть несколько. Например, для задачи выше также правильными были бы решения last(), get(0) и так далее.
Во всех задачах использован один и тот же список.
Не нужно во всех задачах искать логику с точки зрения решения бизнес-задач. Иногда задачи нарочно составлены с ошибками с точки зрения адекватности, сбивающими с толку.
Эти упражнения помогут вам не только размять свой мозг, но и узнать о некоторых особенностях операторов, с которыми вы, возможно, не сталкивались.
Задачи я старался располагать от простых к сложным. Но при решении нужно учитывать, что у каждого свой уровень и опыт.
Ответы к задачам – в конце статьи, но не спешите скроллить вниз!
Не переживайте, если вы не смогли решить все задачи. Они придуманы именно для того, чтобы заставить вас поломать голову. Я сам не смог бы решить их все :)
Итак, приступим.
Задачи
Легкий уровень
Начнем с легких задач. Обратите внимание, что во всех задачах массив одинаковый listOf(1, 3, 3, 2, 4, 1)
Задача 1.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.let { println(it) }//=6
Задача 2.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=5
Задача 3.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=14
Задача 4.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.average()
.let { println(it) }//=2.5
Обратите внимание, что оператор sum() поменялся. Теперь нужно искать не сумму, а среднее значение. В последующих задачах оператор также будет меняться или вовсе пропадать
Задача 5.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.average()
.let { println(it) }//=8.0
Средний уровень
Эти задачи будут чуть посложнее и более каверзные.
Задача 6.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=8
Задача 7.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.let { println(it) }//=72
Задача 8.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.let { println(it) }//=null
Задача 9.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.let { println(it) }//=kotlin.Unit
Задача 10.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=15
Задача 11.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.first()
.let { println(it) }//=java.util.NoSuchElementException
Сложный уровень
Напоследок 3 довольно сложные (с моей точки зрения) задачи.
Задача 12.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=29
Задача 13.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=27
Задача 14.
listOf(1, 3, 3, 2, 4, 1)
//missed operator
.sum()
.let { println(it) }//=6
Замечание: это должен быть не subList().
Ответы
Задача 1.
listOf(1, 3, 3, 2, 4, 1)
.count()
.let { println(it) }//=6
В этой задаче легко догадаться, что в массиве 6 элементов. Чтобы получить это число, нужно воспользоваться оператором count().
Задача 2.
listOf(1, 3, 3, 2, 4, 1)
.takeLast(2)
.sum()
.let { println(it) }//=5
В этой задаче также наглядно видно, что последние 2 числа в сумме дают 5.
Задача 3.
listOf(1, 3, 3, 2, 4, 1)
.map { it }
.sum()
.let { println(it) }//=14
Это, скорее, задача-шутка, так как тут ничего не нужно делать со списком, чтобы получить в ответе 14. Но в условии сказано, что нужно добавить один оператор. Оператор, который ничего не делает, – это map { it }. Другие решения типа also{}, let{it} также принимаются.
Задача 4.
listOf(1, 3, 3, 2, 4, 1)
.distinct()
.average()
.let { println(it) }//=2.5
Здесь ищем среднее значение из неповторяющихся элементов. Тут было бы уместно начать с подсчета среднего значения – сначала у исходного массива, а далее понять, что нужно каким-то способом это значение уменьшать.
Задача 5.
listOf(1, 3, 3, 2, 4, 1)
.map { 8 }
.average()
.let { println(it) }//=8.0
Тут тоже задача-шутка. Сразу понятно, что среднее из текущего листа никак не получить. Один из способов — заменить все числа на необходимые.
Задача 6.
listOf(1, 3, 3, 2, 4, 1)
.filterIndexed { index, value ->
index % 2 == 0
}
.sum()
.let { println(it) }//=8
В этом случае находим сумму из чисел с четными индексами, то есть из списка listOf(1, 2, 4).
Задача 7.
listOf(1, 3, 3, 2, 4, 1)
.fold(1) { acc, x -> acc * x }
.let { println(it) }//=72
//or
listOf(1, 3, 3, 2, 4, 1)
.reduce { acc, x -> acc * x }
.let { println(it) }//=72
Тут из числа 72 видно, что ожидается большой ответ. Также стоит отметить, что нет оператора sum(). Самый быстрый способ найти решение – начать перемножать. Этого можно достичь с помощью операторов fold() и reduce().
Задача 8.
listOf(1, 3, 3, 2, 4, 1)
.getOrNull(7)
.let { println(it) }//=null
В этой задаче нужно было вернуть null. Самый простой способ это сделать — использовать те операторы, которые в наименовании имеют …OrNull(), и подставить туда необходимые для этого условия. Например, вернуть число с индексом больше, чем есть в списке.
Задача 9.
listOf(1, 3, 3, 2, 4, 1)
.forEach { }
.let { println(it) }//=kotlin.Unit
В этой задаче решение состоит в том, чтобы вернуть значение от оператора, который ничего не возвращает, например forEach { }.
Задача 10.
listOf(1, 3, 3, 2, 4, 1)
.indices
.sum()
.let { println(it) }//=15
В этой задаче нужно сложить сумму индексов.
Задача 11.
listOf(1, 3, 3, 2, 4, 1)
.take(0)
.first()
.let { println(it) }//=java.util.NoSuchElementException
Эта задача похожа на задачу 8. То есть нужно каким-то способом вернуть то, чего нет в списке, а конкретно – первый элемент. Так как тут стоит именно first(), а не firstOrNull(), то возникнет ошибка. Простой способ сделать список пустым — это take(0).
Задача 12.
listOf(1, 3, 3, 2, 4, 1)
.mapIndexed { index, value ->
index + value
}
.sum()
.let { println(it) }//=29
В данном случае находится сумма всех чисел и их индексов.
Задача 13.
listOf(1, 3, 3, 2, 4, 1)
.flatMap { 0.rangeTo(it) }
.sum()
.let { println(it) }//=27
Эта задача довольно сложная. Здесь нужно вернуть сумму каждого значения в списке и его предшествующим, начиная с 1. То есть для 1: 1, для 3: 1+ 2+ 3, для 2: 1+ 2 и так далее.
Задача 14.
listOf(1, 3, 3, 2, 4, 1)
.distinctBy { it % 3 }
.sum()
.let { println(it) }//=6
Эта задача, с моей точки зрения, самая сложная. До ее решения непросто догадаться. Тут нужно найти сумму уникальных чисел, но не всех, а меньше 4. Уникальных чисел у нас всего 4: 1, 2, 3, 4. Однако остаток от деления на 3 у числа 4 равен 1. Так же как и у 1. Поэтому число 4 исключается из списка.
Заключение
Ученый-информатик Дональд Кнут утверждает, что решение логических задач выделяет гормоны, которые повышают уровень счастья. Надеюсь, с вами это произошло!
Поделитесь в комментариях – удалось ли вам решить все задачи? Возможно, вы нашли что-то новое, чего раньше знали об операторах, либо не придавали этому значения?
Если вы заметили ошибку, также напишите в об этом комментариях. Там же вы можете предложить более интересные решения, если их удалось найти.