Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.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
什么';在Scala中,还原灯和还原灯之间的区别是什么?_Scala_Collections - Fatal编程技术网

什么';在Scala中,还原灯和还原灯之间的区别是什么?

什么';在Scala中,还原灯和还原灯之间的区别是什么?,scala,collections,Scala,Collections,在Scala中reduceLeft和reduceRight之间有什么区别 val list = List(1, 0, 0, 1, 1, 1) val sum1 = list reduceLeft {_ + _} val sum2 = list reduceRight {_ + _} println { sum2 == sum2 } 在我的代码片段sum1=sum2=4,因此顺序在这里并不重要。Reduce left并不总是等于Reduce right。考虑数组上的非

在Scala中reduceLeft和reduceRight之间有什么区别

  val list = List(1, 0, 0, 1, 1, 1)

  val sum1 = list reduceLeft  {_ + _}   
  val sum2 = list reduceRight {_ + _}

  println { sum2 == sum2 }

在我的代码片段
sum1
=
sum2
=
4
,因此顺序在这里并不重要。

Reduce left并不总是等于Reduce right。考虑数组上的非对称函数。

假设结果相同,性能是一个明显的区别

构建的数据结构具有恒定的头部和尾部访问时间。对于大型列表,向后迭代的效果会更差。

它们什么时候会产生相同的结果 正如莱昂内尔已经指出的那样,
reduceLeft
reduceRight
只有在用于组合元素的函数是关联的情况下才会产生相同的结果(这并不总是正确的,请参见我在底部的注释)。例如,使用函数
(a:Int,b:Int)=>a-b
Seq(1,2,3)
上运行
reduceLeft
reduceRight
时,会得到不同的结果

scala> Seq(1,2,3)
res0: Seq[Int] = List(1, 2, 3) 

scala> res0.reduceLeft(_ - _)
res5: Int = -4

scala> res0.reduceRight(_ - _)
res6: Int = 2
如果我们看看每个函数是如何在列表中应用的,就可以弄清楚为什么会发生这种情况

对于
reduceRight
来说,如果我们要展开调用,调用就是这样的

(1 - (2 - 3))
(1 - (-1))
2
对于
reduceLeft
序列从左侧开始建立

尾部递归 此外,由于
reduceLeft
是使用实现的,因此在对非常大的集合(甚至可能是无限的)进行操作时,它不会堆栈溢出
reduceRight
不是尾部递归的,因此给定足够大的集合,它将产生堆栈溢出

例如,在我的机器上,如果我运行以下命令,就会出现内存不足错误

scala> (0 to 100000000).reduceRight(_ - _)
java.lang.OutOfMemoryError: GC overhead limit exceeded
  at java.lang.Integer.valueOf(Integer.java:832)
  at scala.runtime.BoxesRunTime.boxToInteger(BoxesRunTime.java:65)
  at scala.collection.immutable.Range.apply(Range.scala:61)
  at scala.collection.IndexedSeqLike$Elements.next(IndexedSeqLike.scala:65)
  at scala.collection.Iterator$class.foreach(Iterator.scala:742)
  at scala.collection.AbstractIterator.foreach(Iterator.scala:1194)
  at scala.collection.TraversableOnce$class.reversed(TraversableOnce.scala:99)
  at scala.collection.AbstractIterator.reversed(Iterator.scala:1194)
  at scala.collection.TraversableOnce$class.reduceRight(TraversableOnce.scala:197)
  at scala.collection.AbstractIterator.reduceRight(Iterator.scala:1194)
  at scala.collection.IterableLike$class.reduceRight(IterableLike.scala:85)
  at scala.collection.AbstractIterable.reduceRight(Iterable.scala:54)
  ... 20 elided
但是如果我用
reduceLeft
计算,我得不到OOM

scala> (0 to 100000000).reduceLeft(_ - _)
res16: Int = -987459712
根据JVM默认内存设置,您可能会在系统上得到稍微不同的结果

喜欢左边的版本 因此,由于尾部递归,如果您知道
reduceLeft
reduceRight
将产生相同的值,那么您应该选择
reduceLeft
变量。这通常适用于其他左/右功能,例如
foldRight
foldLeft
(它们只是
reduceRight
reduceLeft
的更通用版本)

什么时候它们真的总是产生相同的结果
关于
reduceLeft
reduceRight
以及您正在使用的函数的关联属性的小说明。我说过,
reduceRight
reduceLeft
只有在操作符是关联的情况下才会产生相同的结果。并非所有集合类型都是如此。尽管这是另一个话题,所以请参考ScalaDoc,但简而言之,您正在使用的函数需要具有可交换性和关联性,以便为所有集合类型获得相同的结果。

了解差异的最佳方法是阅读library/scala/collection/LinearSeqOptimized中的源代码。scala:

  def reduceLeft[B >: A](f: (B, A) => B): B =
    ......
    tail.foldLeft[B](head)(f)

  def reduceRight[B >: A](op: (A, B) => B): B =
    ...... 
    op(head, tail.reduceRight(op))

  def foldLeft[B](z: B)(f: (B, A) => B): B = {
    var acc = z 
    var these = this              
    while (!these.isEmpty) {      
      acc = f(acc, these.head)    
      these = these.tail          
    }                             
    acc
  } 
上面是代码的一些关键部分,您可以看到reduceLeft基于foldLeft,而reduceRight是通过递归实现的


我想reduceLeft的性能更好。

XOR。。。你想说,
list reduceLeft{{{u^}
list reduceRight{{u^}
不同吗?是的,xor是一个很糟糕的例子,但是像{u^-}这样的非对称函数会给出不同的结果。e、 g.list reduceLeft{{u-{u}=-2和list reduceRight{{u-{u}=0该模式解释了这一切。伟大的
  def reduceLeft[B >: A](f: (B, A) => B): B =
    ......
    tail.foldLeft[B](head)(f)

  def reduceRight[B >: A](op: (A, B) => B): B =
    ...... 
    op(head, tail.reduceRight(op))

  def foldLeft[B](z: B)(f: (B, A) => B): B = {
    var acc = z 
    var these = this              
    while (!these.isEmpty) {      
      acc = f(acc, these.head)    
      these = these.tail          
    }                             
    acc
  }