16

Concerning the yield command in Scala and the following example:

val values = Set(1, 2, 3)
val results = for {v <- values} yield (v * 2)

  • Can anyone explain how Scala knows which type of collection to yield into? I know it is based on values, but how would I go about writing code that replicates yield?
  • Is there any way for me to change the type of the collection to yield into? In the example I want results to be of type List instead of Set.
  • Failing this, what is the best way to convert from one collection to another? I know about _:*, but as a Set is not a Seq this does not work. The best I could find thus far is val listResults = List() ++ results.

    Ps. I know the example does not following the recommended functional way (which would be to use map), but it is just an example.

  • Zecrates
    • 2,952
    • 6
    • 33
    • 50
    • 2
      A minor note, while I find map more convenient, I would not call it more or less functional than for, as it is exactly the same thing. for{v <- values} yield (v*2) is compiled as values.map{v => v * 2} (sort of macro expansion). It is definitely not a loop : the implementation of map in Set is responsible for looping if needed, not the for comprehension. – Didier Dupont Jul 23 '11 at 13:44
    • possible duplicate of [How do I easily convert from one collection type to another during a filter, map, flatMap in Scala?](http://stackoverflow.com/questions/5593131/how-do-i-easily-convert-from-one-collection-type-to-another-during-a-filter-map) – om-nom-nom Jun 21 '13 at 15:00

    3 Answers3

    23

    The for comprehensions are translated by compiler to map/flatMap/filter calls using this scheme.

    This excellent answer by Daniel answers your first question.

    To change the type of result collection, you can use collection.breakout (also explained in the post I linked above.)

    scala> val xs = Set(1, 2, 3)
    xs: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
    
    scala> val ys: List[Int] = (for(x <- xs) yield 2 * x)(collection.breakOut)
    ys: List[Int] = List(2, 4, 6)
    

    You can convert a Set to a List using one of following ways:

    scala> List.empty[Int] ++ xs
    res0: List[Int] = List(1, 2, 3)
    
    scala> xs.toList
    res1: List[Int] = List(1, 2, 3)
    

    Recommended read: The Architecture of Scala Collections

    Community
    • 1
    • 1
    missingfaktor
    • 90,905
    • 62
    • 285
    • 365
    • 2
      nice! so you _can_ use `breakOut` with for comprehensions – Kim Stebel Jul 23 '11 at 13:45
    • 1
      How on earth did I miss the toList method?! Thanks a lot, the links are very informative. – Zecrates Jul 23 '11 at 14:17
    • Personally, I prefer [this question](http://stackoverflow.com/q/1052476/53013) to the one you chose to explain how for comprehensions are translated. Then again, you answers the one you linked, and I answered this other, so maybe we are biased. :-) – Daniel C. Sobral Aug 01 '11 at 21:16
    • @Daniel: I never came across that thread before (dates to time when I hadn't even heard of Scala). That is an excellent answer. I upvoted it, and also linked it in my answer. :-) – missingfaktor Aug 02 '11 at 09:24
    • You shouldn't have removed the link to your own answer. It's a good answer too, and, sometimes, people learn something by comparing different answers to the same question. – Daniel C. Sobral Aug 02 '11 at 17:50
    • `breakOut` <- hugely powerful tool. – BAR Feb 17 '15 at 04:16
    4

    If you use map/flatmap/filter instead of for comprehensions, you can use scala.collection.breakOut to create a different type of collection:

    scala> val result:List[Int] = values.map(2*)(scala.collection.breakOut)
    result: List[Int] = List(2, 4, 6)
    

    If you wanted to build your own collection classes (which is the closest thing to "replicating yield" that makes any sense to me), you should have a look at this tutorial.

    Kim Stebel
    • 41,826
    • 12
    • 125
    • 142
    1

    Try this:

    val values = Set(1, 2, 3)
    val results = for {v <- values} yield (v * 2).toList
    
    Pokechu22
    • 4,984
    • 9
    • 37
    • 62
    • While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – gunr2171 Nov 11 '14 at 18:40