Reputation: 173
Sometimes I need to create a collection by mapping another one with different type. For example, some function needs List[_]
as its parameter type, but I need to produce that by mapping a IndexedSeq[_]
:
val r = (1 to n).map { ... }
someFunction(r.toList)
Although I can fulfill that by calling IndexedSeq[_]
's map
method first followed by another call to toList
, this produces a redundant intermediate collection. Is there any way to avoid this redundant step while still keeping code concise?
Upvotes: 3
Views: 158
Reputation: 5069
Have a look at the full signature for map
:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
The key to this is the implicit CanBuildFrom
, which governs how the result collection is generated from the input collection. We can replace the implicit CanBuildFrom
with an explicit one that allows us to build a different result collection.
Even better, we don't even have to write this explicit method! It's there already, in the form of scala.collection.breakOut
. From the ScalaDoc:
Provides a CanBuildFrom instance that builds a specific target collection (To') irrespective of the original collection (From').
So if we pass in collection.breakOut
, we can then specify exactly what we want to the map
method:
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)
Upvotes: 9
Reputation: 28680
The answer to your question is collection.breakOut
, as stated by om-nom-nom in his comment.
breakOut
is an additional argument given to the map
method, and - to keep it simple - it allows to return different types of collections from map
:
def directMapExample(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)(collection.breakOut)
Note, that the following fails at compilation:
def directMapExample2(seq: Seq[Int]): Set[Int] = seq.map(_ * 2)
For details, see https://stackoverflow.com/a/1716558/298389.
Upvotes: 3
Reputation: 10927
Using a view might help?
val r = (1 to n).view.map { … }
someFunction(r.toList)
The map
function is a strict transformer on Range
. However, if you turn it into a view first, then that Range
(which is a non-strict collection) will be wrapped inside an object that implements map
in a non-strict way. The full range of values would only be produced when calling toList
.
Upvotes: 0