1

I have the following code:

case class Person(name: String, age: Int)

object Launcher extends App {

  val people = Option(Seq(Person("Andrii", 20), Person("John", 35), Person("Sam", 15)))

  def filterPeople(list: Option[Seq[Person]]): Boolean =
    list.getOrElse(Nil)
      .exists(_.age < 18)

  assert(filterPeople(people) == true)
}

The question is: can I process Option[Seq[A]] more elegantly and safely without getOrElse(Nil)?

list.getOrElse(Nil)
      .exists(_.age < 18)

I have found another approach to this:

list.exists(_.exists(_.age > 18))

Note: I have Option[Seq[A]] just because of REST contract.

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
  • "Note: I have Option[Seq[A]] just because of REST contract." In this case my suspicion is that you'll quite often need to treat `None` and `Some(Nil)` as equivalent, and `getOrElse(Nil)` has the benefit of working in _all_ of those cases automatically, compared to `fold` or `exists` approaches. So I'd say `getOrElse` is the more elegant and safe approach. – Alexey Romanov Aug 30 '17 at 08:49

2 Answers2

4

Pointed by @NimrodArgov, I would prefer to use pattern matching for checking the list type as it is more readable:

def filterPeople(list: Option[Seq[Person]]): Boolean = {
  list match {
    case Some(people) => people.exists(_.age < 18)
    case None => false
  }
}
Camilo Sampedro
  • 1,306
  • 1
  • 19
  • 32
  • 1
    Use `case None` here, so the compiler can check for complete pattern match. `case _` is a bit dangerous sometimes, better not make it a habit. – Reactormonk Aug 30 '17 at 14:54
  • Thank you, this is the way how it is currently implemented. I agree with you that it is much readable. There is one more option (one man sad that it is idiomatic monads): `list.map(_.exists(_.age < 18)) match { case Some(true) => true case _ => false }`. What do you think? – Andrii Abramov Aug 30 '17 at 14:55
  • I agree with what @Reactormonk says, it is even more readable with the `None` case. Your solution @Andrii is good but, personally, I think that for someone that reads the code it may be a little more confusing to use the `map` and then the pattern matching over a `Option[Boolean]`. – Camilo Sampedro Aug 30 '17 at 15:07
  • @CamiloSampedro I share this option with you. – Andrii Abramov Aug 30 '17 at 15:08
1

Another possibility.

def filterPeople(list: Option[Seq[Person]]): Boolean =
  list.fold(false)(_.exists(_.age < 18))

Tested:

filterPeople(people)  // res0: Boolean = true
filterPeople(None)    // res1: Boolean = false
jwvh
  • 50,871
  • 7
  • 38
  • 64