Understanding the flatMap ad in the list

I just looked at the List.flatMap ad and was surprised by this.

 final override def flatMap[B, That](f: A => GenTraversableOnce[B]) (implicit bf: CanBuildFrom[List[A], B, That]): That 

Where object List defines:

 implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] 

So, if we call flatMap on a List , we get a List , and I don’t see any point in the That type if it will always be displayed on List[B] (due to implicit ).

+5
source share
2 answers

So, if we call flatMap on a List[A] , we get List[A] , and I will not see any point in type That , if it will always be displayed on List[B]

One thing you are missing is that flatMap is not really defined on List[+A] . It is inherited from TraversableLike , which is a feature used by most Scalas collections. Each of these can provide an implicit CanBuildFrom , which can be overridden to provide a different resulting collection.

If you need a little taste of what you can do with a custom CanBuildFrom :

 scala> :pa // Entering paste mode (ctrl-D to finish) import scala.collection.generic.CanBuildFrom import scala.collection.immutable._ import scala.collection.mutable import scala.{List, Vector} implicit val listToVectorCBF = new CanBuildFrom[List[Int], Int, Vector[Int]] { override def apply(from: List[Int]): mutable.Builder[Int, Vector[Int]] = this.apply() override def apply(): mutable.Builder[Int, Vector[Int]] = Vector.newBuilder } // Exiting paste mode, now interpreting. scala> List(1,2,3).flatMap(List(_)) res6: Vector[Int] = Vector(1, 2, 3) 
+5
source

Well ... This implicit CanBuildFrom can be used to directly construct a structure of a different type instead of List and thus save one extra step. consider the following example:

 val list = List(List(1, 2, 3), List(4, 5, 6)) // now if we do a flatmap withtout overriding the implicit CanBuildFrom val newList = list.flatMap(l => l.map(i => (i,i))) // new list will be a List[(Int, Int)] // but what if you wanted a map val newMap = newList.toMap // But you actually needed to traverse the list twice in this case // But we can avoid the second traversal if we chose to override the implicit val newMap2 = list.flatMap(l => l.map(i => (i,i)))(collection.breakout) 
+2
source

All Articles