Juh_
Juh_

Reputation: 15569

filtering only one side of a list/iterable in scala

I'd like to remove only the few last elements of a List (or Seq), and avoid parsing all elements (and avoid applying the filter function to all of them).

Let's say, for example, I have a random strictly increasing list of values:

 import scala.util.Random.nextInt
 val r = (1 to 100).map(_ => nextInt(10)+1).scanLeft(0)(_+_)

And I want to remove the elements greater than, say, 300. I can do this like that:

r.filter(_<300)

but this method parse the whole list. So, is it possible to filter a list only on one end? Something like a filterRight method?

subquestions:

Solutions

I selected @elm solution because it answers the subquestion for general list, not only (strictly) increasing ones. However, the solution of @dcastro looks to be more efficient as it doesn't do 2 reverse

Upvotes: 1

Views: 437

Answers (2)

elm
elm

Reputation: 20435

First note SI-4247 on dropWhile but no dropRightWhile.

Though, a simple implementation that conveys the desired semantics,

def dropRightWhile[A](xs: Seq[A], p: A => Boolean) = 
  xs.reverse.dropWhile(p).reverse

or equivalently

implicit class OpsSeq[A](val xs: Seq[A]) extends AnyVal {
  def dropRightWhile(p: A => Boolean) = xs.reverse.dropWhile(p).reverse
}

Upvotes: 2

dcastro
dcastro

Reputation: 68750

You're looking for something like dropRightWhile, which doesn't exist in the standard library (but has been requested before).

I think your best bet is:

r.takeWhile(_<300)

Since it's an increasing list of values, you can stop performing any checks when you first encounter an element greater than 300

Upvotes: 2

Related Questions