How do I check if a sequence is (not) empty, without assuming it can be consumed twice?
In most cases values.any() and values.none() would work (see also here):
fun doSomething(values: Sequence<Int>) {
if (values.any()) {
println("We have these values: " + values.joinToString(", "))
} else {
println("We have no values")
}
}
but this fails if the sequence can only be consumed once:
val iterator = (0..8).iterator()
val seqFromIterator = iterator.asSequence()
doSomething(seqFromIterator) // throws `IllegalStateException: This sequence can be consumed only once.
val seqConstrainOnce = sequence { yieldAll(0..8) }.constrainOnce()
doSomething(seqConstrainOnce) // throws `IllegalStateException: This sequence can be consumed only once.
You can get around this by creating a new sequence with the iterator of the original (on which we only call hasNext() to check if it's empty, so nothing has been consumed):
fun doSomethingBetter(values: Sequence<Int>) {
val iterator = values.iterator()
if (iterator.hasNext()) {
val iterable = iterator.asSequence()
println("We have these values: " + iterable.joinToString(", "))
} else {
println("We have no values")
}
}
Is this really the best way? It distracts from the purpose of the code, making it less readable. Also, we will end up with a sequence that is always constrained to be consumed once, even if the original was not.