Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Yielding from one type of collection to another

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.

  • like image 819
    Zecrates Avatar asked Jul 23 '11 12:07

    Zecrates


    3 Answers

    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

    like image 115
    missingfaktor Avatar answered Nov 19 '22 08:11

    missingfaktor


    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.

    like image 25
    Kim Stebel Avatar answered Nov 19 '22 10:11

    Kim Stebel


    Try this:

    val values = Set(1, 2, 3)
    val results = for {v <- values} yield (v * 2).toList
    
    like image 1
    user3613516 Avatar answered Nov 19 '22 09:11

    user3613516