HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

zipWith function in Scala

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
zipwithfunctionscala

Problem

My implementation works, but it looks very ugly. Curious to see how it's better implemented.

The zipWith function takes a list of lists (List[List[A]]), or a row with columns if you like. It will then transform this into a column with rows and applies a function List[A]=>B to obtain a List[B]. Hopefully the unit test below explains this better.

test("zipWith"){
    val input = List(List(1,2,3), List(4,5,6), List(7,8,9))
    val expected = List("1::4::7", "2::5::8", "3::6::9")
    assert(zipWith(input)(_.mkString("::")) === expected)
  }


and the implementation is:

def zipWith[A, B](lists: List[List[A]])(f: List[A] => B): List[B] = {
    @tailrec
    def loop(acc: List[B], input: List[List[A]]): List[B] = {
      val init = (Nil: List[List[A]], Nil: List[A])
      val (left, zipped) = input.foldLeft(init)((z, a) => {
        val (tails, heads) = z
        (a.tail :: tails, a.head :: heads)
      })
      if (left.foldLeft(false)(_ || _.isEmpty))
        f(zipped.reverse) :: acc
      else
        loop(f(zipped.reverse) :: acc, left.reverse)
    }

    loop(Nil, lists).reverse
  }

Solution

How about this?

def zipWith[A, B](ts: Traversable[Traversable[A]])(f: Traversable[A] => B): Traversable[B] = {
  ts.transpose.map(f)
}


Example:

scala> zipWith(input)(_.mkString("::"))
res10: Traversable[String] = List(1::4::7, 2::5::8, 3::6::9)

Code Snippets

def zipWith[A, B](ts: Traversable[Traversable[A]])(f: Traversable[A] => B): Traversable[B] = {
  ts.transpose.map(f)
}
scala> zipWith(input)(_.mkString("::"))
res10: Traversable[String] = List(1::4::7, 2::5::8, 3::6::9)

Context

StackExchange Code Review Q#71077, answer score: 3

Revisions (0)

No revisions yet.