Ответ Павла пока приблизился, но он также неэффективен. Два flatMap
с и zipWithIndex
здесь излишни:)
Мое понимание необходимого вывода:
- Результаты содержат все натуральные числа (начиная с 1) хотя бы один раз
- каждое число
n
появляется в выходных данных (n/2) + 1
раз
Как правильно заметил Павел, решение состоит в том, чтобы начать с Stream
, а затем использовать flatMap
:
Stream from 1
Это генерирует Stream
, потенциально бесконечную последовательность, которая производит значения только по требованию. В этом случае он генерирует 1, 2, 3, 4...
вплоть до бесконечности (в теории) или Integer.MAX_VALUE
(на практике)
Потоки могут быть сопоставлены, как с любой другой коллекцией. Например: (Stream from 1) map { 2 * _ }
генерирует поток четных чисел.
Вы также можете использовать flatMap
в потоках, что позволяет сопоставить каждый элемент ввода с нулем или несколькими элементами вывода; это ключ к решению вашей проблемы:
val strm = (Stream from 1) flatMap { n => Stream.fill(n/2 + 1)(n) }
Итак ... Как это работает? Для элемента 3
лямбда { n => Stream.fill(n/2 + 1)(n) }
создаст выходной поток 3,3
. За первые 5 целых чисел вы получите:
1 -> 1
2 -> 2, 2
3 -> 3, 3
4 -> 4, 4, 4
5 -> 5, 5, 5
etc.
и поскольку мы используем flatMap
, они будут объединены, что даст:
1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, ...
Потоки запоминаются, поэтому после расчета заданного значения оно будет сохранено для дальнейшего использования. Тем не менее, все предыдущие значения должны быть рассчитаны как минимум один раз. Если вам нужна полная последовательность, то это не вызовет никаких проблем, но это означает, что генерация S(10796)
с холодного старта будет медленной! (проблема с вашим императивным алгоритмом). Если вам нужно сделать это, то ни одно из решений на данный момент, скорее всего, не подойдет вам.