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 ?
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 ?
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)
}
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).
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.
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.
@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)
Il s'agirait d'un "tuple" d'éléments de même type, je ne peux pas y appliquer map, par exemple.
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
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)
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.
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.
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 ShapelessHList
qui permet la conversion vers et depuis des tuples ( github.com/milessabin/ ). Peut-être que c'est applicable à votre cas d'utilisation.