marcin marcin -4 years ago 140
Scala Question

How can i interleave elements of 2 lists in scala

I'd like to combine two Lists of arbitrary length in such a way that elements from the 2nd List are inserted after every n-th element into the 1st List. If the 1st List length is less than n, no insertion results.

So having

val a = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
val b = List(101,102,103)
val n = 3


I want the resulting List to look like this:

List(1,2,3,101,4,5,6,102,7,8,9,103,10,11,12,13,14,15)


I have this working using a
foldLeft
on
a
, but I'm wondering how the same logic could be accomplished using Scalaz?

Thanks for everyone's answers. They were all helpful to me !

Answer Source

Meet my apomorphism friend

def apo[A, B](v: B)(f: B => Option[(A, Either[B, List[A]])]): List[A] = f(v) match {
   case None => Nil
   case Some((a, Left(b)))   => a :: apo(b)(f)
   case Some((a, Right(as))) => a :: as 
}

Your interleave method can be implemented like this

def interleave[A](period: Int, substitutes: List[A], elems: List[A]): List[A] =
  apo((period, substitutes, elems)){
    case (_, _, Nil)       => None
    case (_, Nil, v :: vs) => Some((v, Right(vs)))
    case (0, x :: xs, vs)  => Some((x, Left((period, xs, vs))))
    case (n, xs, v :: vs)  => Some((v, Left((n - 1, xs, vs))))  
  }

This gives:

scala> interleave(3, b, a)
res1: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103 , 10, 11 , 12, 13, 14, 15)

The good point is the computation ends when a or b are Nil unlike foldLeft. The bad news is interleave is no more tail recursive

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download