Accumulating into different type using for comprehension

#1

As I understand the for comprehension returns an object which is the type of the first object in the outer most loop. The first of the following for comprehensions returns a Set while the second returns a List

// Returns a Set
for{
  y <- Set(10,20,30)
  x <- List(1,2,3)
} yield x+y

// Returns a List
for{
  x <- List(1,2,3)
  y <- Set(10,20,30)
} yield x+y

My question is how am I supposed to select the return value if it is a different type than my first iteration object? In my case I have a List of Lists, and I want to create a Set

for{
  subList <- listOfLists
  element <- subList
} yield as set abs(element)

I don’t want to first create a List and then call .toSet on the result, because the list may be large. And I don’t want to call listOfLists.toSet because this may be large, and I already know there is a minuscule or no chance that it has redundant elements.

My current solution is the following, to include a dummy variable and a dummy Set with a single element, and just ignore the dummy variable. This for comprehension returns a Set of the absolute values of the integers. But it smells of a hack.

for {
  dummy <- Set("unused value")
  subList <- List(List(1, -2, 3),
                  List(10, 20, 30),
                  List(1, 2, -20))
  x <- subList
} yield abs(x)
#2

In Scala 2.12, you can use breakOut:

val s: Set[Int] = (for {
    subList <- List(List(1, -2, 3),
                    List(10, 20, 30),
                    List(1, 2, -20))
    x <- subList
  } yield abs(x))(collection.breakOut)

This replaces the CanBuildFrom part of the collection method, so that the resulting collection type is inferred from context (which is why you will need the type ascription for Set[Int] here.

In Scala 2.13, the CanBuildFrom mechanism is removed (thanks to better type inference and overloads). Here the recommended replacement for breakOut is to use views. I haven’t tested it, but this should work in Scala 2.13 without an intermediate List being created:

(for {
  subList <- List(List(1, -2, 3),
                  List(10, 20, 30),
                  List(1, 2, -20)).view
  x <- subList.view
} yield abs(x)).to(Set)