Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Last element of sequence but with a break if a condition is met

Let say I have a Sequence<Int> of unknown origin (not necessarily from a collection) and unknown but finite size:

val seq = sequenceOf(1, 2, -3, 4, 5, /* ... */)

Assume the sequence is large enough to make it undesirable to turn the whole sequence into a List.

I want to get the last element of the sequence:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

val last = seq.last()

But I also want to catch any "invalid" element that might appear (let’s say negative numbers are invalid) and return the first such element:

val invalid = seq.first { it < 0 }

But how can I do both of those at the same time?

val lastUnlessInvalidElementPresent = seq.firstOrNull { it < 0 } ?: seq.last()

The problem is that ?: seq.last() doesn’t work because by the time firstOrNull has returned null, the whole sequence has been consumed.

I can do this iteratively, but would prefer a functional solution.

>Solution :

You can use fold() with a simple data class that holds your value plus a flag indicating whether you’re still in "get last" mode or already in "encountered an invalid value, let’s keep it" mode:

data class Elem(val value: Int, val valid: Boolean)

fun main() {
    val seq = sequenceOf(1, 2, -3, 4, 5, /* ... */)
    val initial = Elem(0, true)
    val lastUnlessInvalidElementPresent = seq.fold(Elem(0, true), 
       { acc, item -> if (acc.valid && item < 0) { Elem(item, false) }   // first invalid element
                      else if (acc.valid) { Elem(item, true) } // valid element, keep looking
                      else { acc } // already found an invalid element - keep it
       }
    )
    println(lastUnlessInvalidElementPresent)
}

This approach has two disadvantages, though:

  • the fold() will still consume the complete sequence even after encountering an invalid element
  • you need a sensible "default" element to initialize your value

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading