TheDude
TheDude

Reputation: 391

Does scala perform optimisations in chained functions?

val list1 : List[String] = List(....)
val list2 : List[String] = List(....)
val filtered = list1.filter(list2.toSet.contains)

When using the code above, will toSet be called for each item in list1 (in which case I should add another val set2 = list2.toSet, or does the Scala compiler optimizes this in which case the code above will only run toSet once?

Upvotes: 2

Views: 71

Answers (2)

Tomer Shetah
Tomer Shetah

Reputation: 8529

To make sure it is called once, you can just do:

val list1 : List[String] = List(....)
val list2 : List[String] = List(....)
val s: Set[String] = list2.toSet
val filtered = list1.filter(s.contains)

Having said that, you can use intersect method:

list1.intersect(list2)

This method is located on a trait called StrictOptimizedSeqOps, and it has comment in its implementation: // Avoid multiple map lookups So I guess this is optimized.

Upvotes: 2

Alexey Romanov
Alexey Romanov

Reputation: 170713

There are no optimizations needed, toSet can only run once:

  1. eta-expansion rules for converting list2.toSet.contains to a lambda. In this specific case the translation is

    list1.filter({
      val x1 = list2.toSet
      { (y1: String) => x1.contains(y1) }
    })
    
  2. the argument to a method is evaluated before calling it (except for call-by-name parameters, but this isn't one), and to evaluate this block val x1 = list2.toSet is executed first and then { (y1: String) => x1.contains(y1) } is returned.

But of course you can be more explicit if you want.

Upvotes: 4

Related Questions