performance - Why is filter in front of foldLeft slow in Scala? -
i wrote answer first project euler question:
add natural numbers below 1 thousand multiples of 3 or 5.
the first thing came me was:
(1 until 1000).filter(i => (i % 3 == 0 || % 5 == 0)).foldleft(0)(_ + _) but it's slow (it takes 125 ms), rewrote it, thinking of 'another way' versus 'the faster way'
(1 until 1000).foldleft(0){ (total, x) => x match { case if (i % 3 == 0 || % 5 ==0) => + total // add case _ => total //skip } } this faster (only 2 ms). why? i'm guess second version uses range generator , doesn't manifest realized collection in way, doing in 1 pass, both faster , less memory. right?
here code on ideone: http://ideone.com/gbklp
the problem, others have said, filter creates new collection. alternative withfilter doesn't, doesn't have foldleft. also, using .view, .iterator or .tostream avoid creating new collection in various ways, slower here first method used, thought strange @ first.
but, then... see, 1 until 1000 range, size small, because doesn't store each element. also, range's foreach extremely optimized, , specialized, not case of of other collections. since foldleft implemented foreach, long stay range enjoy optimized methods.
(_: range).foreach:
@inline final override def foreach[@specialized(unit) u](f: int => u) { if (length > 0) { val last = this.last var = start while (i != last) { f(i) += step } f(i) } } (_: range).view.foreach
def foreach[u](f: => u): unit = iterator.foreach(f) (_: range).view.iterator
override def iterator: iterator[a] = new elements(0, length) protected class elements(start: int, end: int) extends bufferediterator[a] serializable { private var = start def hasnext: boolean = < end def next: = if (i < end) { val x = self(i) += 1 x } else iterator.empty.next def head = if (i < end) self(i) else iterator.empty.next /** $super * '''note:''' `drop` overridden enable fast searching in middle of indexed sequences. */ override def drop(n: int): iterator[a] = if (n > 0) new elements(i + n, end) else /** $super * '''note:''' `take` overridden symmetric `drop`. */ override def take(n: int): iterator[a] = if (n <= 0) iterator.empty.buffered else if (i + n < end) new elements(i, + n) else } (_: range).view.iterator.foreach
def foreach[u](f: => u) { while (hasnext) f(next()) } and that, of course, doesn't count filter between view , foldleft:
override def filter(p: => boolean): = newfiltered(p).asinstanceof[this] protected def newfiltered(p: => boolean): transformed[a] = new filtered { val pred = p } trait filtered extends transformed[a] { protected[this] val pred: => boolean override def foreach[u](f: => u) { (x <- self) if (pred(x)) f(x) } override def stringprefix = self.stringprefix+"f" }
Comments
Post a Comment