I have a library that uses BitSet, and I need to change Set[Int] type data to use the library.
What comes to mind is to use .toSeq:_*
operations, but I'm not sure this is efficient way to convert from BitSet to Set[Int] or the other way round.
scala> BitSet(Set(1,2,3).toSeq:_*)
res55: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
scala> Set(BitSet(1,2,3).toSeq:_*)
res56: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
Is there a better way?
Scala's Set
hierarchy is a little weird, but it is the case that BitSet
has Set[Int]
as a super type, so you can simply pass a BitSet
to a method that expects a Set[Int]
, etc.
This might not seem to be the case because the Set
you get by default is immutable.Set
(under scala.collection
), while it's possible that the library you're using is working with the BitSet
directly under scala.collection
, not immutable.BitSet
. This isn't the case in your example code, where everything is in immutable
, but I'm not sure how simplified that is.
If you're lucky enough to be working with the immutable
package's versions of both Set
and BitSet
, the BitSet
to Set
direction is trivial:
scala> import scala.collection.immutable.BitSet
import scala.collection.immutable.BitSet
scala> val bs = BitSet(0, 100, 200)
bs: scala.collection.immutable.BitSet = BitSet(0, 100, 200)
scala> def takesSet(s: Set[Int]): Int = s.size
takesSet: (s: Set[Int])Int
scala> takesSet(bs)
res0: Int = 3
If somehow you've got a scala.collection.BitSet
, just use toSet
:
scala> takesSet(scala.collection.BitSet(0, 100, 200).toSet)
res1: Int = 3
For the other direction, your version is fine:
scala> val s = Set(1, 2, 3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> BitSet(s.toSeq: _*)
res2: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
But it's also worth noting that in many cases you can avoid this conversion with some CanBuildFrom
magic:
scala> val bs: BitSet = Set("1", "2", "3").map(_.toInt)(collection.breakOut)
bs: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
This produces the same result as the following:
scala> val bs: BitSet = BitSet(Set("1", "2", "3").map(_.toInt).toSeq: _*)
bs: scala.collection.immutable.BitSet = BitSet(1, 2, 3)
But instead of constructing an intermediate set (and sequence) before the BitSet
, the collection.breakOut
parameter tells the compiler to perform the map using an instance of the CanBuildFrom
type class that will construct the BitSet
directly. Passing a CanBuildFrom
instance explicitly in this way isn't just for map
, either—it'll work with flatMap
, scanLeft
, ++
, and other collections operations that allow you to change the element type.