Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 在Scala中是否有一种安全的方法来转置长度不等的列表?_List_Scala_Transpose - Fatal编程技术网

List 在Scala中是否有一种安全的方法来转置长度不等的列表?

List 在Scala中是否有一种安全的方法来转置长度不等的列表?,list,scala,transpose,List,Scala,Transpose,鉴于以下清单: val l = List(List(1, 2, 3), List(4, 5), List(6, 7, 8)) 如果我尝试转置它,Scala将抛出以下错误: 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)

鉴于以下清单:

val l = List(List(1, 2, 3), List(4, 5), List(6, 7, 8))
如果我尝试转置它,Scala将抛出以下错误:

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...
我想得到以下信息:

List(List(1, 4, 6), List(2, 5, 7), List(3, 8))
写我自己版本的
转置
是最好的方法吗?这就是我想到的:

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
}
更新:我对比较这里提供的不同解决方案的速度感兴趣,因此我将以下小基准放在一起:

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 })
  }
}
我的命令是:

scala PFTranspose 5 out.log
scala ACTranspose 5 out.log
scala ETranspose 5 out.log
我的结果是:

PRTranspose$            10              0               1               1               0
ACTranspose$            9               2               0               0               0
ETranspose$             9               3               2               3               1
我不知道(也无法想象-这不是有点奇怪吗?![见评论中的讨论])一个库函数,但我可以稍微润色一下代码:

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
     | }
这个怎么样:

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

我怀疑在“非矩形”列表上没有定义转置的原因是,从数学上讲,转置操作仅在“矩形结构”上定义良好。转置操作的理想特性是转置(转置(x))==x。在非矩形列表的转置操作的推广中,情况并非如此

另外,请看我在上的帖子,并考虑对非矩形集合执行此操作。你最终会得到数学上不一致的定义,更不用说实现了


我确实同意特殊的“转置”操作通常是有用的,但我也认为它们不应该在标准库中提供,因为它们的精确定义可能会混淆。

这可能是最干净的:

def transpose[T](l: List[List[T]]): List[List[T]] =
     l.flatMap(_.headOption) match {
         case Nil => Nil
         case head => head :: transpose(l.map(_.drop(1)))
     }
或者更高效的修改版本:

def transpose[T](l: List[List[T]]): List[List[T]] =
     l.flatMap(_.headOption) match {
         case Nil => Nil
         case head => head :: transpose(l.collect { case _ :: tail => tail })
     }

这个使用Scala标准Api的一行程序怎么样:

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

这就完成了任务,并且是
O(N*M)
,其中
N
是包装列表的长度,
M
是包装列表中最长列表的长度。

您打算处理输入的第一个列表(列表(1,2,3))不是所有列表的最大大小的情况吗。例如,你如何处理列表(列表(1,2,3)、列表(4,5,99100)、列表(6,7,8))的输入?FWIW,Scala 2.8没有这个错误。但是,如果第一个列表没有其他列表那么好,它确实有一个错误。问得好。在我的特定情况下,后续子列表中内容的顺序并不重要,因此按长度对输入列表的列表进行排序是有效的:myTranspose(l.sort((a,b)=>a.length>b.length))依赖于实现的未记录的特性,如“如果列表从最长到最短排序,它会满足我的要求”这不是我推荐的。现在,这种方法被打破了。我喜欢模式匹配和递归!胡扯。我一直在找,但是弄糊涂了,时间不够了。我更喜欢它而不是我的。这如何可以推广到采用固定大小的组(而不是像这里这样的大小为1的组)。因此,如果组大小为2,第一个示例的结果将是
List(List(1,2,4,5,6,7),List(3,8))
,第二个示例将是
List(List(1,2,4,5,6,7),List(3,99100,8))
我认为这一功能一点也不奇怪;我确实有理由写函数,而函数正是这样做的。我想Andrew的意思是,他对标准库没有这样一个函数感到惊讶。不,我的意思是它看起来很奇怪,因为你似乎丢失了一些信息(你无法反转它来获得你开始使用的东西)。但我想如果我足够努力的话,我可以想象它的用途:)哦,我明白了。我想说的是,如果你有两个以上的列表,它会在类似的情况下用作zip。在我的例子中,我有一个传感器读数列表。转换它们会给我一个普通时间的读数列表,然后我可以将其减少到最小值、最大值和平均值。另一个有用的变化是在短行中不加任何内容,所以对列表[list[Option[a]]进行操作,确保所有列表的长度相同,也就是说,您有一个选项[a]的矩形数组,然后使用库转置。这是一个不同于原始规范的规范,在原始规范中,值通过空插槽“向左下降”,但这是一个潜在的有用变体。哇,这是一个很好的解决方案!
((l map (_.toArray)) toArray).transpose map (_.toList) toList