Let's say there is a function that returns a single nullable return value. For instance:
fun getItem(): String?
I'd like to create a new list of items by calling this function until it returns null
.
My idea would be to write an iterator that iterates the return value until it's null
. However, is there a more elegant or idiomatic way to approach this issue?
CodePudding user response:
Not sure about what would be idiomatic tbh, but you can use a simple while(true)
to achieve it.
val list = mutableListOf<String>()
while (true) getItem()?.let { list = it } ?: break
That basically translates to:
while true (infinite loop).
if getItem() is not null, add it to the list.
if getItem() is null, then break the loop.
CodePudding user response:
Like @Slaw says in the comments, you can use generateSequence
and pass it a reference to your function (or a lambda that calls it if you want) to create a Sequence
that generates values. Terminating when your function returns null
is built-in behaviour:
Returns a sequence which invokes the function to calculate the next value on each iteration until the function returns null.
So you can literally just do generateSequence(::getItem)
to get your "iterator", and call toList
or whatever sequences function you like on it. It's not an actual Iterator
though - you can get one of those by doing toList()
and then calling iterator()
on that.
There's a bunch of ways to get this functionality, but generateSequence
is the simplest I think. If you needed more control, you could chain a takeWhile()
call to make a sequence that terminates on a specific condition/value, or you could use the sequence
builder function to yield
the items you need (say if you wanted to have nulls in there). And there's non-sequence approaches like @Alex.T's "add to a list" trick too (although - I haven't checked - I'd imagine that's what generateSequence -> toList
is doing under the hood)