I\'m learning Scala as my first functional-ish language. As one of the problems, I was trying to find a functional way of generating the sequence S up to n places. S is defined
Pavel's answer has come closest so far, but it's also inefficient. Two flatMap
s and a zipWithIndex
are overkill here :)
My understanding of the required output:
n
appears in the output (n/2) + 1
timesAs Pavel has rightly noted, the solution is to start with a Stream
then use flatMap
:
Stream from 1
This generates a Stream
, a potentially never-ending sequence that only produces values on demand. In this case, it's generating 1, 2, 3, 4...
all the way up to Infinity (in theory) or Integer.MAX_VALUE
(in practice)
Streams can be mapped over, as with any other collection. For example: (Stream from 1) map { 2 * _ }
generates a Stream of even numbers.
You can also use flatMap
on Streams, allowing you to map each input element to zero or more output elements; this is key to solving your problem:
val strm = (Stream from 1) flatMap { n => Stream.fill(n/2 + 1)(n) }
So... How does this work? For the element 3
, the lambda { n => Stream.fill(n/2 + 1)(n) }
will produce the output stream 3,3
. For the first 5 integers you'll get:
1 -> 1
2 -> 2, 2
3 -> 3, 3
4 -> 4, 4, 4
5 -> 5, 5, 5
etc.
and because we're using flatMap
, these will be concatenated, yielding:
1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, ...
Streams are memoised, so once a given value has been calculated it'll be saved for future reference. However, all the preceeding values have to be calculated at least once. If you want the full sequence then this won't cause any problems, but it does mean that generating S(10796)
from a cold start is going to be slow! (a problem shared with your imperative algorithm). If you need to do this, then none of the solutions so far is likely to be appropriate for you.