web-dev-qa-db-fra.com

Conversion d'une collection mutable en immuable

Je recherche un meilleur moyen de convertir un collection.mutable.Seq[T] à collection.immutable.Seq[T].

31
Nikita Volkov

Si vous souhaitez convertir ListBuffer en List, utilisez .toList. Je mentionne cela parce que cette conversion particulière est effectuée en temps constant. Notez cependant que toute utilisation ultérieure de ListBuffer entraînera la copie de son contenu en premier.

Sinon, vous pouvez faire collection.immutable.Seq(xs: _*), en supposant que xs est modifiable, car il est peu probable que vous obteniez de meilleures performances d'une autre manière.

39
Daniel C. Sobral

Comme spécifié:

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

Ajout

Les méthodes natives sont un peu délicates à utiliser. Ils sont déjà définis sur scala.collection.Seq et vous devrez regarder de plus près s'ils renvoient un collection.immutable ou un collection.mutable. Par exemple .toSeq renvoie un collection.Seq qui ne garantit pas la mutabilité. .toIndexedSeq cependant, renvoie un collection.immutable.IndexedSeq donc il semble être bon à utiliser. Je ne suis pas sûr cependant, si c'est vraiment le comportement prévu car il y a aussi un collection.mutable.IndexedSeq.

L'approche la plus sûre serait de la convertir manuellement dans la collection prévue, comme indiqué ci-dessus. Lorsque vous utilisez une conversion native, je pense qu'il est préférable d'ajouter une annotation de type comprenant (mutable/immutable) pour garantir que la collection correcte est renvoyée.

15
Debilski

toList (ou toStream si vous le voulez paresseux) sont le moyen préféré si vous voulez un LinearSeq, car vous pouvez être sûr que ce que vous obtenez est immuable (car List et Stream sont). Il n'y a pas de méthode toVector si vous voulez une IndexedSeq immuable, mais il semble que toIndexedSeq vous donne un vecteur (qui est immuable) la plupart du temps, sinon tout le temps.

Une autre façon consiste à utiliser breakOut. Cela examinera le type que vous visez dans votre type de retour et, si possible, vous obligera. par exemple.

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)

Pour plus d'informations sur une telle magie noire, prenez du café fort et voyez cette question .

6

Si vous travaillez également avec Set et Map, vous pouvez également les essayer, en utilisant TreeSet comme exemple.

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

L'exemple ci-dessus provient du livre Programming in Scala

3
Wang Sheng