**Overview**

It is not unusual that Scala developers struggle in re-conciliating elegant functional programming style with efficient and fast execution. High order collection methods are conducive to very expressive constructs at the cost of poor performance. the zip method is no exception.

Fortunately, the authors of the Scala library have been diligent enough to provide us with alternatives whenever possible. The

*def GenIterable.zip[B](that: GenIterable[B]): CC[(A, B)]*Fortunately, the authors of the Scala library have been diligent enough to provide us with alternatives whenever possible. The

*Tuple2Zippped*class in the run-time package offer a fast implementation of the zip.**Performance Benchmark**

Let's consider the case of two large sized arrays (the same test applies to lists, vectors...) and a function f that iterates on those two arrays. The content of the arrays has no impact on the performance test, therefore we initialize the arrays with random values. The first implementation uses the Scala zipper

val rGen = new scala.util.Random val len = 15000000 val x = Array.tabulate(len)(x => rGen.nextDouble) val y = Array.tabulate(len)(y => rGen.nextDouble) def zipper(x:Array[Double], y:Array[Double], f: (Double,Double) => Double): Array[Double] = x.zip(y).map( x => f(x._1, x._2) )

We compare the performance of the zip method with three "non-elegant" alternative iterators: while loop, the foreach interator and a map method as follows

def whileLoop(x:Array[Double], y:Array[Double], f:(Double,Double) => Double):Array[Double] ={ val z = new Array[Double](x.size) var k = 0; while( k < z.size) { z(k) = f(x(k), y(k)) k += 1 } z } def forEach(x:Array[Double], y:Array[Double], f:(Double,Double)=> Double):Array[Double] = { val z = new Array[Double](x.size) var j = -1 x.foreach( x => { j += 1; z(j) = f(x, y(j)) }) z } def mapIter(x:Array[Double], y:Array[Double], f:(Double,Double)=> Double): Array[Double] = { var i = -1 x.map( x => { i += 1; f(x, y(i)) }) }

**Test**

We perform the test with increasing values of len from 1 to 20 million floating point values as illustrated in the following driver program.

whileLoop(x,y,(x:Double, y:Double)=>x*y) forEach(x,y,(x:Double, y:Double)=>x*y) mapIter(x,y,(x:Double, y:Double)=>x*y) zipper(x,y,(x:Double, y:Double)=>x*y)

The test is performed on i7 8-CPU machine with 32-Gbytes or RAM running Ubuntu with JVM heap settings of -Xmx:4G, although I would expect similar performance results on less powerful computers. The time recorded on the Y-Axis are in milliseconds and the X-Axis represents the number of iterations in millions.

Looking at the bar chart, it is clear that the "ugly" while loop has by far the most efficient execution. The test also confirms that the for loop and map are notoriously slow iterators are discovered and explained in some of my previous posts. It seems the more elegant the implementation, the poorer the performance is. However for small arrays the overhead of the zip methods is negligible.

**Tuple2Zipped to the rescue**

The class scala.runtime.Tuple2Zipped[El1, Repr1, El2, Repr2] is evaluated against the original zip methods on the test array. Let's reuse the array x, and y and compare Array.zip with Tuple2.zipped for the multiplication operator as follow:

x.zip(y).map( t => t._1 * t._2) (x, y).zipped map ( _ * _)