program to handle Heterogeneous Lists in Scala; - 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)

Related

How to find unique elements from list of list of string based on some elements using scala?

I want to filter the list of list based on few elements in it.
pritnln("databind = "datamap)
dataBind = List((List(3,60,90,T3,T6),List(3,90,89,T32,T5),List(3,60,90,T5,T6), List(3,120,89,T32,T5))
I want to filter this list[list[string]] based on unique first elements present in each list. If the first three elements are repeating, I don't want to get it.
My expected output
List((List(3,60,90,T3,T6),List(3,90,89,T32,T5),List(3,120,89,T32,T5))
When I checked in some question they have used for list of tuple
databind.groupBy(v => (v._1, v._2, v._3)).keys.ToList
How can I do this for the above mentioned list ?
Assuming your lists always contain more than 3 elements:
scala> val l = List(List(1,2,3,4), List(2,3,4,5), List(1,2,3,5))
l: List[List[Int]] = List(List(1, 2, 3, 4), List(2, 3, 4, 5), List(1, 2, 3, 5))
scala> l.groupBy(_.take(3))
res1: scala.collection.immutable.Map[List[Int],List[List[Int]]] = Map(List(1, 2, 3) -> List(List(1, 2, 3, 4), List(1, 2, 3, 5)), List(2, 3, 4) -> List(List(2, 3, 4, 5)))
It is then up to you what you do with the groups. For example if you only want the Lists with a unique first 3 elements then:
scala> res1.collect{ case (_, List(l)) => l}
res2: scala.collection.immutable.Iterable[List[Int]] = List(List(2, 3, 4, 5))
Since you want to group lists based on first few elements of every item, you can go about doing the following:
scala> val dataBind = List(List(3,60,90,"T3","T6"),List(3,90,89,"T32","T5"),List(3,60,90,"T5","T6"), List(3,120,89,"T32","T5"))
dataBind: List[List[Any]] = List(List(3, 60, 90, T3, T6), List(3, 90, 89, T32, T5), List(3, 60, 90, T5, T6), List(3, 120, 89, T32, T5))
scala> dataBind.groupBy(_.take(3)).mapValues(_.head).values.toList
res8: List[List[Any]] = List(List(3, 120, 89, T32, T5), List(3, 60, 90, T3, T6), List(3, 90, 89, T32, T5))
You can specify the transformation of your choice inside mapValues method to derive the desired result.

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

flatMap strange behaviour on List of List of Integers

In Scala:
scala> val xs = List(List(1, 3, 5), List(3, 4, 30))
xs: List[List[Int]] = List(List(1, 3, 5), List(3, 4, 30))
scala> xs flatMap {x => x + 1}
<console>:9: error: type mismatch;
found : Int(1)
required: String
xs flatMap {x => x + 1}
Why?
The simplest solution is to flat your list before executing map:
xs.flatten.map { _ + 1 }
The reason for your error is that flatMap doesn't flatten the collection on which you execute it, it flattens the results returning by the function in its argument.
String in that error message is an unfortunately misleading inference.
The error the compiler ideally would have given you is
found : Int => Int
required: Int => List[Int]
x in the flatMap is a List[Int] not an Int, two solutions come to mind:
scala> xs.flatMap(identity).map(_ + 1)
res2: List[Int] = List(2, 4, 6, 4, 5, 31)
scala> xs.flatMap(_.map(_ + 1))
res3: List[Int] = List(2, 4, 6, 4, 5, 31)

Complement method for .last when working with List objects?

Working with Lists in Scala I would like a simple way to get all elements but the last element. Is there a complementary method for .last similar to .head/.tail complement?
I'd rather not dirty up code with something like:
val x: List[String] = List("abc", "def", "ghi")
val allButLast: List[String] = x.reverse.tail.reverse
// List(abc, def)
Thanks.
init selects all elements but the last one.
List API for init.
scala> List(1,2,3,4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> res0.init
res1: List[Int] = List(1, 2, 3, 4)
The 4 related methods here are head, tail, init, and last.
head and last get the first and final member, whereas
tail and init exclude the first and final members.
scala> val list = (0 to 10).toList
list: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> list.head
res0: Int = 0
scala> list.tail
res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> list.init
res2: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> list.last
res3: Int = 10
You should also take care, because all 4 of them are unsafe on the empty list and will throw exceptions.
These methods are defined on GenTraversableLike, which List implements.
That's init.
link to Scaladoc: http://www.scala-lang.org/api/2.11.5/index.html#scala.collection.immutable.List#init:Repr
def init: List[A]
Selects all elements except the last.
Also, note that it's defined in GenTraversableLike, so pretty much any Scala collection has this method.
For dropping off any number of items from the end of a list consider dropRight,
val xs = (1 to 5).toList
xs.dropRight(1)
List(1, 2, 3, 4)
xs.dropRight(2)
List(1, 2, 3)
xs.dropRight(10)
List()

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 !
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)