How can i interleave elements of 2 lists in scala - 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 !

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

This gets very simple with zipAll. Moreover, you are able to choose the amount of elements of the second array (in this case 1):
val middle = b.grouped(1).toList
val res = a.grouped(n).toList.zipAll(middle, Nil, Nil)
res.filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)
Or if you prefer, one-liner:
a.grouped(n).toList.zipAll(b.map(List(_)), Nil, Nil).filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)
You can also make an implicit class, so you could call a.interleave(b, 3) or with an optional thrid parameter a.interleave(b, 3, 1).

How about this:
def process[A](xs: List[A], ys: List[A], n: Int): List[A] =
if(xs.size <= n || ys.size == 0) xs
else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)
scala> process(a,b,n)
res8: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> val a = List(1,2,3,4,5,6,7,8,9,10,11)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
scala> process(a,b,n)
res9: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11)
scala> val a = List(1,2,3,4,5,6,7,8,9)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> process(a,b,n)
res10: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9)
scala> val a = List(1,2,3,4,5,6,7,8)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
scala> process(a,b,n)
res11: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8)
Your request is "If the 1st List length is less than n, no insertion results", then my code should change to:
def process[A](xs: List[A], ys: List[A], n: Int): List[A] =
if(xs.size < n || ys.size == 0) xs
else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)

What about:
def interleave[A](xs: Seq[A], ys: Seq[A], n: Int): Seq[A] = {
val iter = xs grouped n
val coll = iter zip ys.iterator flatMap { case (xs, y) => if (xs.size == n) xs :+ y else xs }
(coll ++ iter.flatten).toIndexedSeq
}
scala> interleave(a, b, n)
res34: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> interleave(1 to 2, b, n)
res35: Seq[Int] = Vector(1, 2)
scala> interleave(1 to 6, b, n)
res36: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102)
scala> interleave(1 to 7 b, n)
res37: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7)
scala> interleave(1 to 7, Nil, n)
res38: Seq[Int] = Vector(1, 2, 3, 4, 5, 6, 7)
scala> interleave(1 to 7, Nil, -3)
java.lang.IllegalArgumentException: requirement failed: size=-3 and step=-3, but both must be positive
It is short, but it is not the most efficient solution. If you call it with Lists for example, the append-operations (:+ and ++) are expensive (O(n)).
EDIT: I'm sorry. I notice now, that you want to have a solution with Scalaz. Nevertheless the answer may be useful therefore I won't delete it.

Without Scalaz and recursion.
scala> a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if (as.size == n) as ++ e else as }.toList
res17: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
Generic way:
def filled[T, A, That](a: A, b: Seq[T], n: Int)(implicit bf: CanBuildFrom[A, T, That], a2seq: A => Seq[T]): That = {
val builder = bf()
builder.sizeHint(a, a.length / n)
builder ++= a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if(as.size == n ) as ++ e else as }
builder.result()
}
Usage:
scala> filled("abcdefghijklmnopqrstuvwxyz", "1234", 3)
res0: String = abc1def2ghi3jkl4mnopqrstuvwxyz
scala> filled(1 to 15, 101 to 103, 3)
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> filled(1 to 3, 101 to 103, 3)
res70: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101)
scala> filled(1 to 2, 101 to 103, 3)
res71: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)

here's the one you want:
import scala.annotation.tailrec
#tailrec
final def interleave[A](base: Vector[A], a: List[A], b: List[A]): Vector[A] = a match {
case elt :: aTail => interleave(base :+ elt, b, aTail)
case _ => base ++ b
}
...
interleave(Vector.empty, a, b)

Related

program to handle Heterogeneous Lists in Scala;

I have to find out the maximum/minimum from this list:
val data= List(List(1,2), List(3,4,91,9,10),11,211,456,345)
From some stack over flow example ,i can see below solution:
val flatdata=data.collect{case i:Int => List(i); case l # a :: b => l}.flatten
[
But this is giving error]
Can some one please help.
want the solution using pure scala and not spark
Let's go through your code in more detail:
sacla> val data= List(List(1,2), List(3,4,91,9,10),11,211,456,345)
data: List[Any] = List(List(1, 2), List(3, 4, 91, 9, 10), 11, 211, 456, 345)
The type of data is a List[Any] because the list is not one specific type. The compiler tries to infer the type, but since Int and List[Int] aren't compatible, it resolves to Any.
scala> data.collect{case i:Int => List(i); case l # a :: b => l}
res0 List[List[Any]] = List(List(1, 2), List(3, 4, 91, 9, 10), List(11), List(211), List(456), List(345))
This second part, tries to consolidate the entries to be a List of Lists. It matches an Int and wraps it in a List.
However, you see the type here is still List[List[Any]].
Now the last part, the .flatten
scala> res0.flatten
res1: List[Any] = List(1, 2, 3, 4, 91, 9, 10, 11, 211, 456, 345)
This takes you from a List[List[Any] to List[Any].
Now the key part here is that if you try to call .max or .min on this list, it won't work. Since there is no such Ordering for Any.
<console>:13: error: No implicit Ordering defined for Any.
The fix will be to force the this type in the original collect call.
scala> data.collect{case i:Int => List(i); case l : List[Int] => l}
res6: List[List[Int]] = List(List(1, 2), List(3, 4, 91, 9, 10), List(11), List(211), List(456), List(345))
scala> .flatten
res7: List[Int] = List(1, 2, 3, 4, 91, 9, 10, 11, 211, 456, 345)
scala> .max
res8: Int = 456
scala> res7.min
res9: Int = 1
One thing wrong with your code is that the result is List[Any], which isn't going to be terribly useful.
This gives a compiler warning but produces a List[Int] result.
data.flatMap{case li:List[Int] => li; case i:Int => List(i)}
There's nothing wrong with your code, it evaluates fine. Not sure what error you're getting.
scala> val data= List(List(1,2), List(3,4,91,9,10),11,211,456,345)
data: List[Any] = List(List(1, 2), List(3, 4, 91, 9, 10), 11, 211, 456, 345)
scala> data.collect{case i:Int => List(i); case l # a :: b => l}
res0: List[List[Any]] = List(List(1, 2), List(3, 4, 91, 9, 10), List(11), List(211), List(456), List(345))
scala> data.collect{case i:Int => List(i); case l # a :: b => l}.flatten
res1: List[Any] = List(1, 2, 3, 4, 91, 9, 10, 11, 211, 456, 345)

How to split a collection into groups using the calculation of member as a predicate

I have a method that collect the consecutive number with the difference of no more than some number (2 in my example). This code is working just fine but it does zipping every time it is called, so I wonder if there is any better solution to this thanks.
def myGrouper(sortedData: Seq[Int], maxDif: Int): Seq[Seq[Int]] = sortedData match {
case Nil => Nil
case _ =>
val (grouped, rest) = sortedData.zipWithIndex.span{
case (num, idx) =>
if (idx > 1) Math.abs(sortedData(idx-1) - num) <= maxDif
else true
}
Seq(grouped.map(_._1)) ++ myGrouper(rest.map(_._1), maxDif)
}
val myList = Seq(1, 2, 3, 7, 8, 10, 15, 17, 19)
val maxDif = 2
println(myGrouper(myList, maxDif))
Below is the result from running this code
myList: Seq[Int] = List(1, 2, 3, 7, 8, 10, 15, 17, 19)
maxDif: Int = 2
List(List(1, 2, 3), List(7, 8, 10), List(15, 17, 19))
res0: Unit = ()

How to repeatedly swap elements in scala list?

I have a List
val a= List(1,2,3,4,5,6,7)
I want to consecutive swap the elements How can I do this?
Expected ans is
List(2,1,4,3,6,5,7)
scala> List(1,2,3,4,5,6,7).grouped(2).flatMap(_.reverse).toList
res10: List[Int] = List(2, 1, 4, 3, 6, 5, 7)
The key is to use grouped while working on groups:
val a= List(1,2,3,4,5,6,7)
a.grouped(2).flatMap{_.reverse}.toList
//res0: List[Int] = List(2, 1, 4, 3, 6, 5, 7)
Sliding can also be used :
scala> List(1,2,3,4,5,6).sliding(2,2).foldLeft(List[Int]()){(r,c) => r :+ c.last :+ c.head }.toList
res0: List[Int] = List(2, 1, 4, 3, 6, 5)
Or
scala> List(1,2,3,4,5,6).sliding(2,2).flatMap(_.reverse).toList
res1: List[Int] = List(2, 1, 4, 3, 6, 5)
A recursive function for repeated swaps, as follows,
def f(xs: List[Int]): List[Int] = {
xs match {
case Nil => Nil
case x :: Nil => List(x)
case x :: y :: ys => y :: x :: f(ys)
}
}
Note that
f(a)
List(2, 1, 4, 3, 6, 5, 7)
f(f(a)) == a
true

Merging streams in scala

I need help with merging two streams into one. The output has to be as follows:
(elem1list1#elem1list2, elem2list1#elem2list2...)
and the function breaks if any of streams is empty
def mergeStream(a: Stream[A], b: Stream[A]):Stream[A] =
if (a.isEmpty || b.isEmpty) Nil
else (a,b) match {
case(x#::xs, y#::ys) => x#::y
}
Any clue how to fix it?
You can also zip two Streams together, which will truncate the longer Stream, and flatMap them out of the tuples:
a.zip(b).flatMap { case (a, b) => Stream(a, b) }
Though I cannot speak to it's efficiency.
scala> val a = Stream(1,2,3,4)
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val b = Stream.from(3)
b: scala.collection.immutable.Stream[Int] = Stream(3, ?)
scala> val c = a.zip(b).flatMap { case (a, b) => Stream(a, b) }.take(10).toList
c: List[Int] = List(1, 3, 2, 4, 3, 5, 4, 6)
def mergeStream(s1: Stream[Int], s2: Stream[Int]): Stream[Int] = (s1, s2) match {
case (x#::xs, y#::ys) => x #:: y #:: mergeStream(xs, ys)
case _ => Stream.empty
}
scala> mergeStream(Stream.from(1), Stream.from(100)).take(10).toList
res0: List[Int] = List(1, 100, 2, 101, 3, 102, 4, 103, 5, 104)
You can use interleave from scalaz:
scala> (Stream(1,2) interleave Stream.from(10)).take(10).force
res1: scala.collection.immutable.Stream[Int] = Stream(1, 10, 2, 11, 12, 13, 14, 15, 16, 17)

Scala: How to sort an array within a specified range of indices?

And I have a comparison function "compr" already in the code to compare two values.
I want something like this:
Sorting.stableSort(arr[i,j] , compr)
where arr[i,j] is a range of element in array.
Take the slice as a view, sort and copy it back (or take a slice as a working buffer).
scala> val vs = Array(3,2,8,5,4,9,1,10,6,7)
vs: Array[Int] = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
scala> vs.view(2,5).toSeq.sorted.copyToArray(vs,2)
scala> vs
res31: Array[Int] = Array(3, 2, 4, 5, 8, 9, 1, 10, 6, 7)
Outside the REPL, the extra .toSeq isn't needed:
vs.view(2,5).sorted.copyToArray(vs,2)
Updated:
scala 2.13.8> val vs = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
val vs: Array[Int] = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
scala 2.13.8> vs.view.slice(2,5).sorted.copyToArray(vs,2)
val res0: Int = 3
scala 2.13.8> vs
val res1: Array[Int] = Array(3, 2, 4, 5, 8, 9, 1, 10, 6, 7)
Split array into three parts, sort middle part and then concat them, not the most efficient way, but this is FP who cares about performance =)
val sorted =
for {
first <- l.take(FROM)
sortingPart <- l.slice(FROM, UNTIL)
lastPart <- l.takeRight(UNTIL)
} yield (first ++ Sorter.sort(sortingPart) ++ lastPart)
Something like that:
def stableSort[T](x: Seq[T], i: Int, j: Int, comp: (T,T) => Boolean ):Seq[T] = {
x.take(i) ++ x.slice(i,j).sortWith(comp) ++ x.drop(i+j-1)
}
def comp: (Int,Int) => Boolean = { case (x1,x2) => x1 < x2 }
val x = Array(1,9,5,6,3)
stableSort(x,1,4, comp)
// > res0: Seq[Int] = ArrayBuffer(1, 5, 6, 9, 3)
If your class implements Ordering it would be less cumbersome.
This should be as good as you can get without reimplementing the sort. Creates just one extra array with the size of the slice to be sorted.
def stableSort[K:reflect.ClassTag](xs:Array[K], from:Int, to:Int, comp:(K,K) => Boolean) : Unit = {
val tmp = xs.slice(from,to)
scala.util.Sorting.stableSort(tmp, comp)
tmp.copyToArray(xs, from)
}