Reputation: 20591
I'm wondering what is idiomatic way to applying some operation on the List
if it is not empty, and return empty List
(Nil
) if list is empty.
val result= myList match {
case Nil => Nil // this one looks bad for me
case nonEmpty => myService.getByFilters(nonEmpty)
}
Just using map
operation on the list will trigger loop, but I want to achieve same result as map
for Option
type - i.e. do something only once if List
is non-empty, and do nothing if List
is empty
Upvotes: 1
Views: 258
Reputation: 20435
By invoking each filter service separately,
myList.flatMap(filter => myService.getByFilters(List(filter)))
it gets an empty list if myList
is empty. If performance may be a matter, consider also a parallel version with
myList.par
Upvotes: 0
Reputation: 16338
There is method headOption
in List
, so you could use option semantic to lift List
to Option[List]
:
import scala.collection.TraversableLike
implicit class TraversableOption[T <: TraversableLike[_, T]](traversable: T) {
def opt: Option[T] = traversable.headOption.map(_ => traversable)
}
you can use it as:
val result = myList.opt.fold[List[Int]](Nil)(myService.getByFilters)
Upvotes: 0
Reputation: 16422
I think your design is not quite right perhaps. You should be just able to pass any list into the getByFilters
function and it should just handle lists of any length. So there should be no need for these sorts of checks.
If the design change is not possible there is nothing wrong with if
:
val result = if(myList.isEmpty) Nil else myService.getByFilters(myList)
It's idiomatic because if
returns values. Maybe there are other clean ways, I don't know.
If you just want to require non empty list argument you can use HList
or alternatively, you can use this trick:
def takesNonEmptyList[T](head: T, tail: T *): List[T] = head :: tail.toList
You can do something fake to make it seem look idiomatic, but I would not recommend it. It's unclear and unnecessary complication:
def getByFilters(xs: List[Int]) = xs.filter(_ % 2 == 0)
val res = l.headOption.map(_ :: l.tail).map(getByFilters).getOrElse(Nil)
println(res)
prints List(2, 4)
Upvotes: 3
Reputation: 6242
If you really want it, you can just implement your own semantic:
implicit class MySpecialList[T](xs: List[T]) {
def mapIfNotEmpty[R](f: List[T] ⇒ List[R]): List[R] =
if (xs.isEmpty) Nil else f(xs)
}
def getStuff(xs: List[Int]) = xs.map(_ + " OK")
val x: List[Int] = List(1,2,3)
val y: List[Int] = List()
def main(args: Array[String]): Unit = {
val xx = x.mapIfNotEmpty(getStuff) // List("1 OK", "2 OK", "3 OK")
val yy = y.mapIfNotEmpty(getStuff) // List()
}
Upvotes: 0