Converting mutable collection to immutable

36,541

Solution 1

If you want to convert ListBuffer into a List, use .toList. I mention this because that particular conversion is performed in constant time. Note, though, that any further use of the ListBuffer will result in its contents being copied first.

Otherwise, you can do collection.immutable.Seq(xs: _*), assuming xs is mutable, as you are unlikely to get better performance any other way.

Solution 2

As specified:

def convert[T](sq: collection.mutable.Seq[T]): collection.immutable.Seq[T] = 
  collection.immutable.Seq[T](sq:_*)

Addition

The native methods are a little tricky to use. They are already defined on scala.collection.Seq and you’ll have to take a close look whether they return a collection.immutable or a collection.mutable. For example .toSeq returns a collection.Seq which makes no guarantees about mutability. .toIndexedSeq however, returns a collection.immutable.IndexedSeq so it seems to be fine to use. I’m not sure though, if this is really the intended behaviour as there is also a collection.mutable.IndexedSeq.

The safest approach would be to convert it manually to the intended collection as shown above. When using a native conversion, I think it is best practice to add a type annotation including (mutable/immutable) to ensure the correct collection is returned.

Solution 3

toList (or toStream if you want it lazy) are the preferred way if you want a LinearSeq, as you can be sure what you get back is immutable (because List and Stream are). There's no toVector method if you want an immutable IndexedSeq, but it seems that toIndexedSeq gives you a Vector (which is immutable) most if not all of the time.

Another way is to use breakOut. This will look at the type you're aiming for in your return type, and if possible oblige you. e.g.

scala> val ms = collection.mutable.Seq(1,2,3)
ms: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)

scala> val r: List[Int] = ms.map(identity)(collection.breakOut)
r: List[Int] = List(1, 2, 3)

scala> val r: collection.immutable.Seq[Int] = ms.map(identity)(collection.breakOut)
r: scala.collection.immutable.Seq[Int] = Vector(1, 2, 3)

For more info on such black magic, get some strong coffee and see this question.

Solution 4

If you are also working with Set and Map you can also try these, using TreeSet as an example.

import scala.collection.mutable

val immutableSet = TreeSet(blue, green, red, yellow)

//converting a immutable set to a mutable set
val mutableSet = mutable.Set.empty ++= immutableSet

//converting a mutable set back to immutable set
val anotherImmutableSet = Set.empty ++ mutableSet

The above example is from book Programming in Scala

Share:
36,541
Nikita Volkov
Author by

Nikita Volkov

Updated on February 02, 2020

Comments

  • Nikita Volkov
    Nikita Volkov over 4 years

    I'm looking for a best way of converting a collection.mutable.Seq[T] to collection.immutable.Seq[T].