web-dev-qa-db-fra.com

Séquences multiples zip

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?

34

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).

7
kiritsuku

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))**
7
igx

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.]

5
Debilski

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.

2
ziggystar

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.

1
Mark Lister