Dada la siguiente lista:¿Hay una manera segura en la Scala de transponer una lista de listas de longitud desigual?
val l = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))
Si trato de transposición, Scala arrojará el siguiente error:
scala> List.transpose(l)
java.util.NoSuchElementException: head of empty list
at scala.Nil$.head(List.scala:1365)
at scala.Nil$.head(List.scala:1362)
at scala.List$$anonfun$transpose$1.apply(List.scala:417)
at scala.List$$anonfun$transpose$1.apply(List.scala:417)
at scala.List.map(List.scala:812)
at scala.List$.transpose(List.scala:417)
at .<init>(<console>:6)
at .<clinit>(<console>)
at RequestResult...
Esto se debe a List.transpose
asume listas de igual longitud y por lo tanto utiliza el método head
:
def transpose[A](xss: List[List[A]]): List[List[A]] = {
val buf = new ListBuffer[List[A]]
var yss = xss
while (!yss.head.isEmpty) {
buf += (yss map (_.head))
yss = (yss map (_.tail))
}
buf.toList
}
me gustaría obtener la siguiente:
List(List(1, 4, 6), List(2, 5, 7), List(3, 8))
¿Está escribiendo mi propia versión de transpose
la mejor manera de hacerlo? Esto es lo que ocurrió:
def myTranspose[A](xss: List[List[A]]): List[List[A]] = {
val buf = new ListBuffer[List[A]]
var yss = xss
while (!yss.head.isEmpty) {
buf += (yss filter (!_.isEmpty) map (_.head))
yss = (yss filter (!_.isEmpty) map (_.tail))
}
buf.toList
}
Actualización: que estaba interesado en la comparación de la velocidad de las diferentes soluciones que aquí se ofrecen, por lo que poner juntos los siguientes poca referencia:
import scala.testing.Benchmark
import scala.collection.mutable.ListBuffer
trait Transpose extends Benchmark {
def transpose[Int](xss: List[List[Int]]): List[List[Int]] = Nil
val list: List[List[Int]] = List(List(1,2,3), Nil, List(4,5,99,100), List(6,7,8))
def run = {
val l = transpose(list)
println(l)
l
}
}
object PRTranspose extends Transpose {
override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = {
val buf = new ListBuffer[List[Int]]
var yss = xss
while (!yss.head.isEmpty) {
buf += (yss filter (!_.isEmpty) map (_.head))
yss = (yss filter (!_.isEmpty) map (_.tail))
}
buf.toList
}
}
object ACTranspose extends Transpose {
override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = {
val b = new ListBuffer[List[Int]]
var y = xss filter (!_.isEmpty)
while (!y.isEmpty) {
b += y map (_.head)
y = y map (_.tail) filter (!_.isEmpty)
}
b.toList
}
}
object ETranspose extends Transpose {
override def transpose[Int](xss: List[List[Int]]): List[List[Int]] = xss.filter(!_.isEmpty) match {
case Nil => Nil
case ys: List[List[Int]] => ys.map{ _.head }::transpose(ys.map{ _.tail })
}
}
Mi comandos fueron:
scala PFTranspose 5 out.log
scala ACTranspose 5 out.log
scala ETranspose 5 out.log
Mis resultados fueron los siguientes:
PRTranspose$ 10 0 1 1 0
ACTranspose$ 9 2 0 0 0
ETranspose$ 9 3 2 3 1
¿Tiene la intención de manejar el caso donde la primera lista (Lista (1,2,3)) de la entrada no es el tamaño máximo de todas las listas. P.ej. ¿cómo se maneja la entrada de la Lista (Lista (1,2,3), Lista (4,5,99,100), Lista (6,7,8))? –
FWIW, Scala 2.8 no tiene este error. –
Pero tiene un error si la primera lista no es tan buena como cualquier otra. –