96 votes

Convertir une liste Scala en tuple ?

Comment puis-je convertir une liste comportant (disons) 3 éléments en un tuple de taille 3 ?

Par exemple, disons que j'ai val x = List(1, 2, 3) et je veux le convertir en (1, 2, 3) . Comment puis-je faire ?

1 votes

Ce n'est pas possible (sauf "à la main") AFAIK. Étant donné def toTuple(x: List[Int]): R quel doit être le type de R ?

7 votes

Si cela n'a pas besoin d'être fait pour un tuple de taille arbitraire (c'est-à-dire comme une méthode hypothétique présentée ci-dessus), envisagez de x match { case a :: b :: c :: Nil => (a, b, c); case _ => (0, 0, 0) } et noter que le type résultant est fixé à Tuple3[Int,Int,Int]

2 votes

Bien que ce que vous cherchez à faire ne soit pas possible avec List vous pourriez regarder dans Shapeless HList qui permet la conversion vers et depuis des tuples ( github.com/milessabin/ ). Peut-être que c'est applicable à votre cas d'utilisation.

62voto

cyrillk Points 319

Vous pouvez le faire en utilisant des extracteurs scala et le filtrage ( lien ) :

val x = List(1, 2, 3)

val t = x match {
  case List(a, b, c) => (a, b, c)
}

qui renvoie un tuple

t: (Int, Int, Int) = (1,2,3)

Vous pouvez également utiliser un opérateur joker si vous n'êtes pas sûr de la taille de la liste.

val t = x match {
  case List(a, b, c, _*) => (a, b, c)
}

4 votes

Dans le contexte de cette solution, les plaintes concernant la sécurité des types signifient que vous pourriez obtenir un MatchError au moment de l'exécution. Si vous voulez, vous pouvez essayer d'attraper cette erreur et faire quelque chose si la liste n'a pas la bonne longueur. Une autre caractéristique intéressante de cette solution est que la sortie ne doit pas nécessairement être un tuple, elle peut être une de vos propres classes personnalisées ou une transformation des nombres. Je ne pense pas que vous puissiez faire cela avec des listes autres que des listes (vous devrez donc effectuer une opération .toList sur l'entrée).

0 votes

Vous pouvez le faire avec n'importe quel type de séquence Scala en utilisant la syntaxe + :. N'oubliez pas non plus d'ajouter une fonction attrape-tout

62voto

pelotom Points 14817

Vous ne pouvez pas faire ça de manière sûre. Pourquoi ? Parce qu'en général, nous ne pouvons pas connaître la longueur d'une liste avant l'exécution. Mais la "longueur" d'un tuple doit être encodée dans son type, et donc connue au moment de la compilation. Par exemple, (1,'a',true) a le type (Int, Char, Boolean) qui est du sucre pour Tuple3[Int, Char, Boolean] . La raison pour laquelle les tuples ont cette restriction est qu'ils doivent être capables de gérer des types non-homogènes.

0 votes

Existe-t-il une liste de taille fixe d'éléments ayant le même type ? Sans importer de bibliothèques non standard, comme shapeless, bien sûr.

1 votes

@davips pas à ma connaissance, mais c'est assez facile de faire le sien, par ex. case class Vec3[A](_1: A, _2: A, _3: A)

0 votes

Il s'agirait d'un "tuple" d'éléments de même type, je ne peux pas y appliquer map, par exemple.

49voto

evantill Points 316

Un exemple utilisant informe :

import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled

Note : le compilateur a besoin de certaines informations de type pour convertir la liste en HList. C'est la raison pour laquelle vous devez passer des informations de type à la fonction toHList méthode

18voto

virtualirfan Points 101

Sans forme 2.0 modification de certaines syntaxes. Voici la solution mise à jour en utilisant shapeless.

import shapeless._
import HList._
import syntax.std.traversable._

val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled

Le principal problème est que le type de .toHList doit être spécifié à l'avance. Plus généralement, les tuples étant limités dans leur arité, la conception de votre logiciel pourrait être mieux servie par une solution différente.

Néanmoins, si vous créez une liste de manière statique, envisagez une solution comme celle-ci, qui utilise également shapeless. Ici, nous créons directement une HList et le type est disponible au moment de la compilation. Rappelez-vous qu'une HList possède les caractéristiques des types List et Tuple, c'est-à-dire qu'elle peut avoir des éléments de différents types comme un Tuple et peut être mappée sur d'autres opérations comme les collections standard. Les HLists prennent un peu de temps pour s'y habituer, alors allez-y doucement si vous êtes nouveau.

scala> import shapeless._
import shapeless._

scala> import HList._
import HList._

scala>   val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil

scala>   val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)

scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)

8voto

Mechanical snail Points 8589

On ne peut pas faire ça de manière sûre. En Scala, les listes sont longueur arbitraire des séquences d'éléments d'un certain type. Pour autant que le système de type le sache, x peut être une liste de longueur arbitraire.

En revanche, l'arité d'un tuple doit être connue au moment de la compilation. Cela violerait les garanties de sécurité du système de types si l'on autorisait l'attribution de x à un type de tuple.

En fait, pour des raisons techniques, les tuples Scala étaient limitées à 22 éléments mais cette limite n'existe plus en 2.11. La limite de la classe de cas a été levée en 2.11. https://github.com/scala/scala/pull/2305

Il serait possible de coder manuellement une fonction qui convertit les listes comportant jusqu'à 22 éléments et qui lève une exception pour les listes plus importantes. Le support des modèles de Scala, une fonctionnalité à venir, rendrait cela plus concis. Mais il s'agirait d'un affreux hack.

0 votes

Le type résultant de cette fonction hypothétique serait-il Any ?

0 votes

La limite de la classe de cas a été levée en 2.11. github.com/scala/scala/pull/2305

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X