5

I am looking for a way to efficiently transform content and type of the collection.

For example apply map to a Set and get result as List.

Note that I want to build result collection while applying transformation to source collection (i.e. without creating intermediate collection and then transforming it to desired type).

So far I've come up with this (for Set being transformed into List while incrementing every element of the set):

val set = Set(1, 2, 3)

val cbf = new CanBuildFrom[Set[Int], Int, List[Int]] {
    def apply(from: Set[Int]): Builder[Int, List[Int]] = List.newBuilder[Int]
    def apply(): Builder[Int, List[Int]] = List.newBuilder[Int]
}

val list: List[Int] = set.map(_ + 1)(cbf)

... but I feel like there should be more short and elegant way to do this (without manually implementing CanBuildFrom every time when I need to do this).

Any ideas how to do this?

Eugene Loy
  • 12,224
  • 8
  • 53
  • 79

2 Answers2

7

This is exactly what scala.collection.breakOut is for—it'll conjure up the CanBuildFrom you need if you tell it the desired new collection type:

import scala.collection.breakOut

val xs: List[Int] = Set(1, 2, 3).map(_ + 1)(breakOut)

This will only traverse the collection once. See this answer for more detail.

Community
  • 1
  • 1
Travis Brown
  • 138,631
  • 12
  • 375
  • 680
1

I think that this might do what you want, though I am not 100% positive so maybe someone could confirm:

(Set(1, 2, 3).view map (_ + 1)).toList

view creates, in this case, an IterableView, which, when you call map on it, does not actually perform the mapping. When toList is called, the map is performed and a list is built with the results.

Owen
  • 38,836
  • 14
  • 95
  • 125
  • Interesting ... this works and avoids the problem that you'd get doing e.g. `(Set(1, 2, 3) map (_ % 2)).toList`, which would delete duplicate entries (i.e. the result is `List(1, 0)` rather than the expected `List(1, 0, 1)`, which you get when using the view). – Urban Vagabond Jun 09 '14 at 22:14
  • @UrbanVagabond , This is because first part (Set(1, 2, 3).view creates a lazy iterator when doing the map it creates a Set (which does not includes the duplicates) and after that it creates the List. in this case we create a new set and than a list . what he wanted to do is in one pass . otherwise he could simply do Set(1, 2, 3).toList.map(_+1) – igx Jun 10 '14 at 06:30