11
votes

Y a-t-il un moyen sûr de Scala pour transposer une liste de listes de longueur inégale?

Compte tenu de la liste suivante: xxx pré>

Si j'essaie de le transposer, Scala lancera l'erreur suivante: P>

PRTranspose$            10              0               1               1               0
ACTranspose$            9               2               0               0               0
ETranspose$             9               3               2               3               1


5 commentaires

Avez-vous l'intention de gérer le cas où la première liste (liste (1,2,3)) de l'entrée n'est pas la taille maximale de toutes les listes. Par exemple. Comment gérez-vous l'entrée de la liste (liste (1,2,3), liste (4,5,99 100), liste (6,7,8))?


FWIW, SCALAA 2.8 n'a pas ce bogue.


Mais, il a un bogue si la première liste n'est pas au moins aussi grande que d'autres.


Bonne question. Dans mon cas particulier, l'ordre du contenu dans les sous-sublistes suivants n'a pas d'importance, alors trier les listes de la liste d'entrée par des travaux de longueur: MyTranspose (L.Sort ((A, B) => A.Length> B.Longueur) )


Compter sur une idiosyncrasie non documentée de la mise en œuvre comme «Cela fait ce que je veux si les listes sont triées les plus longues au plus courtes» n'est pas quelque chose que je recommande. Et cette approche est maintenant cassée.


5 Réponses :


3
votes

Je ne sais pas (et je ne peux pas imaginer - N'est-ce pas un peu étrange ?! [Voir discussion en commentaires]) Une fonction de bibliothèque, mais je peux polir le code un peu:

scala> def transpose(x: List[List[Int]]): List[List[Int]] = {
     |   val b = new ListBuffer[List[Int]]
     |   var y = x filter (!_.isEmpty)
     |   while (!y.isEmpty) {
     |     b += y map (_.head)
     |     y = y map (_.tail) filter (!_.isEmpty)
     |   }
     |   b.toList
     | }


6 commentaires

Je ne pense pas que c'est une fonctionnalité impaire du tout; J'ai définitivement eu raison d'écrire des fonctions qui l'ont fait exactement


Je pense que Andrew a voulu dire qu'il est surpris que la bibliothèque standard n'ait pas une telle fonction.


Non, je voulais vraiment dire qu'il semblait étrange, car vous semblez perdre des informations (vous ne pouvez pas l'inverser pour obtenir ce que vous avez commencé). Mais je suppose que je peux imaginer des utilisations si j'essaie assez fort :)


Oh je vois. Je dirais que cela serait utilisé dans des situations similaires comme zip si vous avez plus de 2 listes. Dans mon cas, j'ai une liste de listes de lectures de capteurs. Les transposer me donne une liste de listes des lectures à des moments communs, que je peux ensuite réduire aux valeurs minimales, maximales et moyennes.


Une autre variation utile consiste à renvoyer les lignes courtes sans rien, alors utilisez la liste [Liste [option [A]]]], assurez-vous que toutes les listes sont de même longueur, c'est-à-dire que vous avez une gamme rectangulaire d'option [A ], utilisez ensuite la transposition de la bibliothèque. Ceci est une spécification différente de votre original, dans lequel les valeurs "tombent à gauche" à travers des machines à sous vide, mais c'est une variation potentiellement utile.


Avertissement: Ce n'est pas un algorithme de sécurité de pile. Vous ne pouvez l'exécuter que avec une matrice relativement petite.



9
votes

Que diriez-vous de cela:

    scala> def transpose[A](xs: List[List[A]]): List[List[A]] = xs.filter(_.nonEmpty) match {    
         |     case Nil    =>  Nil
         |     case ys: List[List[A]] => ys.map{ _.head }::transpose(ys.map{ _.tail })
         | }
    warning: there were unchecked warnings; re-run with -unchecked for details
    transpose: [A](xs: List[List[A]])List[List[A]]

    scala> val ls = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))
    ls: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))

    scala> transpose(ls)
    res0: List[List[Int]] = List(List(1, 4, 6), List(2, 5, 7), List(3, 8))

    scala> val xs = List(List(1,2,3), List(4,5,99,100), List(6,7,8))
xs: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 99, 100), List(6, 7, 8))

scala> transpose(xs)
res1: List[List[Int]] = List(List(1, 4, 6), List(2, 5, 7), List(3, 99, 8), List(100))


3 commentaires

J'aime le motif correspondant et la récursion!


les rats. Je cherchais ça mais je me suis confié et j'ai manqué de temps. Je préfère le mien.


Comment cela peut-il être généralisé pour prendre des groupes de taille fixe (plutôt que de taille 1 comme ici). Donc, si la taille du groupe est 2, le résultat du premier exemple serait Liste (liste (1,2,4,5,6,7), liste (3,8)) et la seconde Exemple serait liste (liste (1,2,4,5,6,7), liste (3 9.100,8))



4
votes

Je soupçonne que la TRANSE TRANSPOSE n'est pas définie sur une liste "non rectangulaire" des listes est dû au fait que la transposition de transposition n'est pas bien définie uniquement sur "Structures rectangulaires". Une propriété souhaitable d'une opération de transposition est celle transpose (transpose (x)) == x. Ce n'est pas le cas dans votre généralisation de l'opération Transpose sur la liste non rectangulaire des listes.

Aussi, jetez un coup d'œil à mon message sur Transposer une collection arbitraire - de- Collections à Scala et pensez à le faire pour des collections non rectangulaires-de collections. Vous vous retrouverez avec des définitions incohérentes mathématiquement, laissez des implémentations seules.

Je conviens que les opérations "transpositions" idiosyncratiques sont souvent utiles, mais je pense également qu'elles ne devraient pas être mises à disposition dans des bibliothèques standard en raison de la confusion potentielle concernant leurs définitions précises.


0 commentaires

0
votes

Ceci est probablement le plus propre: xxx

ou une version modifiée est encore plus efficace: xxx


0 commentaires

0
votes

Que diriez-vous de cette doublure à l'aide de l'API standard de Scala:

((l map (_.toArray)) toArray).transpose map (_.toList) toList


1 commentaires

Wow, c'est une belle solution!