J'essaie de Zip
plusieurs séquences pour former une longue tuple:
val ints = List(1,2,3)
val chars = List('a', 'b', 'c')
val strings = List("Alpha", "Beta", "Gamma")
val bools = List(true, false, false)
ints Zip chars Zip strings Zip bools
Ce que je reçois:
List[(((Int, Char), String), Boolean)] =
List((((1,a),Alpha),true), (((2,b),Beta),false), (((3,c),Gamma),false))
Cependant, je voudrais obtenir une séquence de plat tuples:
List[(Int, Char, String, Boolean)] =
List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))
Je peux maintenant faire:
List(ints, chars, strings, bools).transpose
Mais il retourne faiblement typée List[List[Any]]
. Aussi je peux faire (ints, chars, strings).zipped
, mais zipped
fonctionne uniquement sur 2-tuples et 3-tuples.
Existe-t-il un moyen de zip (arbitraire) de séquences de longueur égale facilement?
Je créerais une classe qui représente les ensembles de données:
case class DataSet(int: Int, char: Char, string: String, bool: Boolean)
Cela apporte des noms plus jolis à accéder aux valeurs au lieu de _N
Nous avons dans des tuples. Si les listes peuvent avoir des tailles différentes, le plus court doit être choisi:
val min = List(ints, chars, strings, bools).map(_.size).min
Maintenant, il est possible d'extraire les données:
val dataSets = (0 until min) map { i => DataSet(ints(i), chars(i), strings(i), bools(i)) }
Lorsque les listes d'origine peuvent contenir beaucoup de valeurs, il est préférable de les rendre à un IndexedSeq
afin que l'heure d'accès soit O (1).
Je pense que la correspondance de modèle est une bonne option
val ints = List(1,2,3)
val chars = List('a', 'b', 'c')
val strings = List("Alpha", "Beta", "Gamma")
val bools = List(true, false, false)
(ints Zip chars Zip strings Zip bools) map { case (((i,c),s),b) => (i,c,s,b)}
**res1: List[(Int, Char, Java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))**
ou vous pouvez ajouter du type aussi
(ints Zip chars Zip strings Zip bools) map {case (((i:Int,c:Char),s:String),b:Boolean) => (i,c,s,b)}
**res2: List[(Int, Char, Java.lang.String, Boolean)] = List((1,a,Alpha,true), (2,b,Beta,false), (3,c,Gamma,false))**
En utilisant informe , vous pouvez faire:
import shapeless.Tuples._
val ints = (1, 2, 3)
val chars = ('a', 'b', 'c')
val megatuple = (ints, chars)
val megahlist = (megatuple hlisted) map hlisted
val transposed = (mhlist transpose) map tupled tupled
scala> transposed
res: ((Int, Char), (Int, Char), (Int, Char)) = ((1,a),(2,b),(3,c))
(Pas sûr, s'il y a plus d'implication définie qui vous permet d'éviter les conversions map
et de retour de retour)
[ Modifier : Cette partie n'est plus vraie.
Notez que les documents infables disent, seules les conversions jusqu'à Tuple4
sont actuellement pris en charge. Vous devriez créer manuellement les hlistes alors.]
Je partage l'opinion de Jesper que cela n'est pas possible en général, car chaque Tuple ARITY est représentée en tant que classe de classe distincte dans le code source, vous devez donc écrire un code séparé pour y accéder sauf si vous utilisez un générateur de code.
Mais je veux ajouter une autre solution possible. Si vous souhaitez conserver la saisie de vos entrées TUPLE, mais vous êtes autrement intéressé par un type de collection plus de collection, peut-être que des hétérogènes (listes hétérogènes) sont peut-être pour vous. Vous pouvez Google hlist scala
pour les implémentations et les explications.
En utilisant collections de produits
scala> ints flatZip chars flatZip strings flatZip bools
res0: org.catch22.collections.immutable.CollSeq4[Int,Char,String,Boolean] =
CollSeq((1,a,Alpha,true),
(2,b,Beta,false),
(3,c,Gamma,false))
Cela fonctionne actuellement pour ARITY 1 - 22. Comme vous pouvez le constater, les types sont préservés.