27

Is there anything in Scala like,

condition ? first_expression : second_expression;

that I can use within map function in scala? I want to be able to write something like this:

val statuses = tweets.map(status => status.isTruncate? //do nothing | status.getText())

If the inline function is not possible, how can I write a condition within map?

Shaido
  • 27,497
  • 23
  • 70
  • 73
Lisa
  • 3,121
  • 15
  • 53
  • 85

2 Answers2

46

The ? operator, sometimes called the ternary operator is not necessary in Scala, since it is subsumed by a regular if-else expression:

val x = if (condition) 1 else 2

To use this in a map, you can use flatMap and then return an Option on either side of the if-else. Since Option is implicitly convertible to Iterable, the effect is that the list is flattened, and the Nones are filtered:

val statuses = tweets.flatMap(status => if (status.isTruncate) None else Some(status.getText))

This is equivalent to using map and then flatten:

val statuses = tweets.map(status => if (status.isTruncate) None else Some(status.getText)).flatten

More idiomatically, you can use collect, which allows you to filter and map in one step using a partial function:

val statuses = tweets.collect {
    case status if !status.isTruncate => status.getText
}

You can also do this in 2 steps using filter and map:

val statuses = tweets.filterNot(_.isTruncate).map(_.getText)

The downside here is that this will iterate over the list twice, which may be undesirable. If you use view, you can use this same logic and only iterate over the list once:

val statuses = tweets.view.filterNot(_.isTruncate).map(_.getText)
Ben Reich
  • 16,222
  • 2
  • 38
  • 59
  • 1
    Since the question is tagged [tag:apache-spark], `tweets` is likely an RDD. In that case there is no `filterNot` method, and no `views`. However, RDDs are lazy by nature, so there is no need for `views` either. – Daniel Darabos Apr 04 '15 at 10:49
  • We can also use `withFilter` to do the filtering only in the subsequent operations like `map`. https://www.scala-lang.org/api/current/scala/collection/Seq.html#withFilter(p:A=>Boolean):scala.collection.WithFilter[A,CC] – juanmirocks Apr 09 '20 at 08:57
2

you can filter and then map like,

  val statuses = tweets.filter(_.isTruncate).map(status=> status.getText())
S.Karthik
  • 1,389
  • 9
  • 21
  • 5
    This is _not_ the preferred way to approach resolving the problem. It causes the filtered items to be traversed two times; all items for the filter pass and then the successfully filtered items a second time. Given a large list and a substantial percentage which is kept with the filter, your solution is also quite inefficient. BTW, Ben's answer's last line uses a view which can move your solution to becoming efficient. – chaotic3quilibrium May 10 '16 at 00:09