web-dev-qa-db-fra.com

Puis-je compresser plus de deux listes ensemble dans Scala?

Étant donné la liste Scala suivante:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

Comment puis-je avoir:

List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))

Étant donné que Zip ne peut être utilisé que pour combiner deux listes, je pense que vous auriez besoin d'itérer/réduire la liste principale d'une manière ou d'une autre. Sans surprise, ce qui suit ne fonctionne pas:

scala> l reduceLeft ((a, b) => a Zip b)
<console>:6: error: type mismatch;
 found   : List[(String, String)]
 required: List[String]
       l reduceLeft ((a, b) => a Zip b)

Des suggestions sur la façon de procéder? Je pense qu'il me manque une façon très simple de le faire.

pdate: Je cherche une solution qui peut prendre une liste de N listes avec M éléments chacune et créer une liste de M TupleNs.

Mise à jour 2: En fin de compte, il est préférable que mon cas d'utilisation spécifique ait une liste de listes plutôt qu'une liste de tuples, donc j'accepte la réponse de citrouille. C'est aussi le plus simple, car il utilise une méthode native.

85
pr1001

Je ne pense pas qu'il soit possible de générer une liste de tuples de taille arbitraire, mais la fonction de transposition fait exactement ce dont vous avez besoin si cela ne vous dérange pas d'obtenir une liste de listes à la place.

33
copumpkin
scala> (List(1,2,3),List(4,5,6),List(7,8,9)).zipped.toList
res0: List[(Int, Int, Int)] = List((1,4,7), (2,5,8), (3,6,9))

Pour référence future.

200
Xorlev

Donc, ce morceau de code ne répondra pas aux besoins de l'OP, et pas seulement parce qu'il s'agit d'un fil de quatre ans, mais il répond à la question du titre, et peut-être que quelqu'un peut même le trouver utile.

Pour compresser 3 collections:

as Zip bs Zip cs map { 
  case ((a,b), c) => (a,b,c)
}
28
Bijou Trouvaille

Oui, avec Zip .

11
Harold L

transpose fait l'affaire. Un algorithme possible est:

def combineLists[A](ss:List[A]*) = {
    val sa = ss.reverse;
    (sa.head.map(List(_)) /: sa.tail)(_.Zip(_).map(p=>p._2 :: p._1))
}

Par exemple:

combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))

La réponse est tronquée à la taille de la liste la plus courte dans l'entrée.

combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))
6
W.P. McNeill

Je ne pense pas que ce soit possible sans être répétitif. Pour une raison simple: vous ne pouvez pas définir le type de retour de la fonction que vous demandez.

Par exemple, si votre entrée était List (List (1,2), List (3,4)), le type de retour serait List [Tuple2 [Int]]. S'il avait trois éléments, le type de retour serait List [Tuple3 [Int]], et ainsi de suite.

Vous pouvez retourner List [AnyRef], ou même List [Product], puis créer un tas de cas, un pour chaque condition.

Quant à la transposition générale des listes, cela fonctionne:

def transpose[T](l: List[List[T]]): List[List[T]] = l match {
  case Nil => Nil
  case Nil :: _ => Nil
  case _ => (l map (_.head)) :: transpose(l map (_.tail))
}
5
Daniel C. Sobral

Si vous ne voulez pas emprunter la route applicative scalaz/cats/(insérez votre bibliothèque fonctionnelle préférée ici), la correspondance de modèle est la voie à suivre, bien que le (_, _) la syntaxe est un peu gênante avec l'imbrication, alors changeons-la:

import scala.{Tuple2 => &}

for (i1 & i2 & i3 & i4 <- list1 Zip list2 Zip list3 Zip list4) yield (i1, i2, i3, i4)

Le & est un choix arbitraire ici, tout ce qui ressemble à Nice infix devrait le faire. Vous obtiendrez probablement quelques sourcils levés lors de la révision du code.

Il devrait également fonctionner avec tout ce que vous pouvez Zip (par exemple Futures)

5
L4Z

Scala traite toutes ses différentes tailles de tuples comme différentes classes (Tuple1, Tuple2, Tuple3, Tuple4, ..., Tuple22) alors qu'ils héritent tous du trait Product, ce trait ne contient pas suffisamment d'informations pour réellement utiliser les valeurs de données des différentes tailles de tuples si elles peuvent toutes être renvoyées par la même fonction. (Et les génériques de scala ne sont pas assez puissants pour gérer ce cas non plus.)

Votre meilleur pari est d'écrire des surcharges de la fonction Zip pour les 22 tailles de tuple. Un générateur de code vous aiderait probablement avec cela.

5
Ken Bloom

product-collections a une opération flatZip jusqu'à arity 22.

scala> List(1,2,3) flatZip Seq("a","b","c") flatZip Vector(1.0,2.0,3.0) flatZip Seq(9,8,7)
res1: com.github.marklister.collections.immutable.CollSeq4[Int,String,Double,Int] = 
CollSeq((1,a,1.0,9),
        (2,b,2.0,8),
        (3,c,3.0,7))
2
Mark Lister

Avec Scalaz:

import scalaz.Zip
import scalaz.std.list._

// Zip 3
Zip[List].ap.Tuple3(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"))

// Zip 4
Zip[List].ap.Tuple4(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"))

// Zip 5
Zip[List].ap.Tuple5(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"))

Pour plus de 5:

// Zip 6
Zip[List].ap.apply6(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"))((_, _, _, _, _, _))

// Zip 7
Zip[List].ap.apply7(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"),
                    List("a7", "b7"))((_, _, _, _, _, _, _))

...

// Zip 12
Zip[List].ap.apply12(List("a1", "b1"),
                     List("a2", "b2"),
                     List("a3", "b3"),
                     List("a4", "b4"),
                     List("a5", "b5"),
                     List("a6", "b6"),
                     List("a7", "b7"),
                     List("a8", "b8"),
                     List("a9", "b9"),
                     List("a10", "b10"),
                     List("a11", "b11"),
                     List("a12", "b12"))((_, _, _, _, _, _, _, _, _, _, _, _))
0
ZhekaKozlov