Is there any method that does the same as map () but creates a different type of container?
Sometimes I need to create a collection by mapping another to a different type. For example, some function requires List[_]
as its parameter type, but I need to create this by matching a IndexedSeq[_]
:
val r = (1 to n).map { ... }
someFunction(r.toList)
While I can accomplish this by calling a method IndexedSeq[_]
map
and then another call toList
, this creates a redundant intermediate collection. Is there a way to avoid this redundant step while keeping the code concise?
source to share
View full signature for map
:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
The key to this is implicit CanBuildFrom
, which determines how the result collection is created from the input collection. We can replace the implicit one CanBuildFrom
with an explicit one, which allows us to build a different collection of results.
Better yet, we don't even need to write this explicit method! He's already there, in uniform scala.collection.breakOut
. From ScalaDoc:
Provides a CanBuildFrom instance that creates a specific target collection (To) regardless of the source collection (From).
So, if we go to collection.breakOut
, we can specify exactly what we want with the method map
:
val x = IndexedSeq(1,2,3,4,5)
x.map[Int, List[Int]](_ * 2)(collection.breakOut)
> res6: List[Int] = List(2, 4, 6, 8, 10)
source to share
The answer to your question collection.breakOut
is as pointed out by om-nom-nom in his comment.
breakOut
- an additional argument provided to the method map
and - to keep it simple - it allows you to return different collection types from map
:
def directMapExample(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)(collection.breakOut)
Please note that the following fails when compiled:
def directMapExample2(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)
See fooobar.com/questions/1413 / ... for details .
source to share
Can using a view help?
val r = (1 to n).view.map { … }
someFunction(r.toList)
The function map
is a strict transformer on Range
. However, if you first include it in the view, then Range
(which is a lax collection) will be wrapped inside an object that is loosely implemented map
. The full range of values will only be generated when called toList
.
source to share