Scala List difference with index information - scala

I have two Lists
val l1 = List(1,2,3)
val l2 = List(1,3,3)
with
l1.diff(l2)
I can find the difference in the list; at the same time I am interested in index where the difference found also; can i know what is the solution in scala ?
Note : All the time both the list size is going to be same.

You can just add indexes to both lists and diff then:
val diff = l1.zipWithIndex.diff(l2.zipWithIndex)
-> List((2,1)) // different value is 2 and index is 1

val indexes = (l1 zip l2 zipWithIndex).filter(x => x._1._1 != x._1._2).map(_._2)
val indexesWithDiffValues = (l1 zip l2 zipWithIndex).filter(x => x._1._1 != x._1._2)
this code will give you a list of indexes you want.

Another way which shows you very easy which list and where you can find the value:
l1.diff(l2).map(v => (v, l1.indexOf(v), l2.indexOf(v)))
// res6: List[(Int, Int, Int)] = List((2,1,-1))

Related

Getting the largest integer value from many lists

I want to get the maximum integer value of a bunch of lists.
How can I do this? Keep in mind, some of the lists maybe empty.
I tried something but I was getting:
java.lang.UnsupportedOperationException: empty.max
So I just have a bunch of lists like:
val l1 = List.empty
val l2 = List(1,2,3)
val l3 = List(4,5,6)
val l4 = List(10)
I am doing this currently:
(l1 ++ l2 ++ l3).max
The max may not exist if all the lists are empty, so we can model the result as an Option[Int].
Here's a simple way of doing it:
val max: Option[Int] = List(l1, l2, l3, l4).flatten match {
case Nil => None
case list => Some(list.max)
}
Performing an operation on a List if not empty is a common use case, so there's an ad-hoc combinator that you can use alternatively, reduceOption, as suggested by Jean Logeart's answer:
If you're into one-liners, you can do:
val max: Option[Int] = List(l1, l2, l3, l4).flatten.reduceOption(_ max _)
although I would prefer the first (more verbose) solution, as I personally find it easier to read.
If instead you want to have a default result, you can fold over the flattened List starting with your default:
val max: Int = List(l1, l2, l3, l4).flatten.foldLeft(0)(_ max _) // 0 or any default
or alternatively, just prepend a 0 to your original solution
val max = (0 :: l1 ++ l2 ++ l3).max
If all the lists can be empty:
val max: Option[Int] = Seq(l1, l2, l3, l4).flatten.reduceOption(_ max _)
Pretty much all of the other answers are using flatten or flatMap to create an intermediate list. If all of your lists are quite large, that's needless memory overhead. My solution uses iterators to avoid the extra allocation in the middle.
val list = List(l1, l2, l3, l4)
val max = list.iterator.flatMap(_.iterator).reduceOption(_ max _)
As pointed out in a comment, the .flatMap(_.iterator) can actually be replaced by a flatten. Since it's being called on an iterator, the result is another iterator, rather than a complete list.
If you are running into an exception where ALL of the lists are empty, then this will solve that:
(0 :: l1 ++ l2 ++ l3).max
Assuming you just want to default to 0 if they are all empty.
Here is a way you can use Options and a try/catch to find the max:
scala> val l = List(List.empty, List(1,2,3), List(4,5,6), List(10))
l: List[List[Int]] = List(List(), List(1, 2, 3), List(4, 5, 6), List(10))
scala> l.flatMap(x => try{ Some(x.max) } catch {case _ => None}).max
res0: Int = 10
In light of the comments below: don't use exceptions for control flow. I would recommend using Gabriele Petronella's solution.

How to get combined lists from two list using scala?

I have two lists
val list1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
val list2 = List(("AAA",List("a","b","c")),("BBB",List("c","d","e")))
I want to match first element from list2 with first element of list1 and get combined list.
I want output as -
List((List("AAA"),"B1","C1",List("a","b","c")))
How to get above output using Scala??
This is what I came up with:
scala> val l1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
l1: List[(List[String], String, String)] = List((List(AAA),B1,C1), (List(BBB),B2,C2))
scala> val l2 = List((List("AAA"), List("a", "b", "c")), (List("BBB"), List("c", "d", "e")))
l2: List[(String, List[String])] = List((AAA,List(a, b, c)), (BBB,List(c, d, e)))
scala> l1.collectFirst {
| case tp => l2.find(tp2 => tp2._1.head == tp._1.head).map(founded => (tp._1, tp._2, tp._3, founded._2))
| }.flatten
res2: Option[(List[String], String, String, List[String])] = Some((List(AAA),B1,C1,List(a, b, c)))
You can use collectFirst to filter values you don't want and on every tuple you use find on the second list and map it into the tuple you want.
A couple of notes, this is horrible, I don't know how you got with a Tuple4 in the first place, I personally hate all that tp._* notation, it's hard to read, think about using case classes to wrap all that into some more manageable structure, second I had to use .head which in case of empty list will throw an exception so you may want to do some checking before that, but as I said, I would completely review my code and avoid spending time working on some flawed architecture in the first place.
You can use zip to combine both the list
val list1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
val list2 = List(("AAA",List("a","b","c")),("BBB",List("c","d","e")))
val combinedList = (list1 zip list2)
combinedList.head will give you the desired result
It will give the combined list from which you can get the first element

Scala - List to List of tuples

Beginner here.
Sorry but I did'nt found an answer so I ask the question here.
I want to know how to do this by using the Scala API :
(blabla))( -> List(('(',2),(')',2))
Currently I have this :
"(blabla))(".toCharArray.toList.filter(p => (p == '(' || p == ')')).sortBy(x => x)
Output :
List((, (, ), ))
Now how can I map each character to the tuples I describe ?
Example for a general case :
"t:e:s:t" -> List(('t',2),('e',1),('s',1),(':',3))
Thanks
val source = "ok:ok:k::"
val chars = source.toList
val shorter = chars.distinct.map( c => (c, chars.count(_ == c)))
//> shorter : List[(Char, Int)] = List((o,2), (k,3), (:,4))
Classic groupBy . mapValues use case:
scala> val str = "ok:ok:k::"
str: String = ok:ok:k::
scala> str.groupBy(identity).mapValues(_.size) // identity <=> (x => x)
res0: scala.collection.immutable.Map[Char,Int] = Map(k -> 3, : -> 4, o -> 2)
I like sschaef's solution very much, but I was wondering if anyone could weigh in on how efficient that solution is compared to this one:
scala> val str = "ok:ok:k::"
str: String = ok:ok:k::
scala> str.foldLeft(Map[Char,Int]().withDefaultValue(0))((current, c) => current.updated(c, current(c) + 1))
res29: scala.collection.immutable.Map[Char,Int] = Map(o -> 2, k -> 3, : -> 4)
I think my solution is slower. If we have n total occurrences and m unique values:
My solution: we have the fold left over all occurrences or n. For each of these occurrences we look up once to find the current count and then again to create the updated the map. I'm assuming that the creating of the updated map is constant time.
Total complexity: n * 2m or O(n*m)
sschaef's solution: we have the groupBy which I'm assuming just adds entries onto a list without checking the map (so for all values this would be a constant time look up plus appending to the list) so n. Then for the mapValues it probably iterates over the unique values and grabs the size for each key's list. I'm assuming that getting the size of each entry's list is constant time.
Total complexity: O(n + m)
Does this seem correct or am I mistaken in my assumptions?

How to remove duplicates from a list then sort by most frequent

I have a list with assorted keywords that may repeat. I need to generate a list with distinct keywords but sorted by the frequency of which they appeared on the original list.
How would be the idiomatic Scala for that? Here is a working but ugly implementation:
val keys = List("c","a","b","b","a","a")
keys.groupBy(p => p).toList.sortWith( (a,b) => a._2.size > b._2.size ).map(_._1)
// List("a","b","c")
Shorter version:
keys.distinct.sortBy(keys count _.==).reverse
That is not particular efficient, however. The groupBy version ought to perform better, though it can be improved:
keys.groupBy(identity).toSeq.sortBy(_._2.size).map(_._1)
One can also get rid of the reverse in the first version by declaring an Ordering:
val ord = Ordering by (keys count (_: String).==)
keys.distinct.sorted(ord.reverse)
Note that reverse in this version just produces a new Ordering that works in the opposite manner of the original. This version also suggests a way to get better performance:
val freq = collection.mutable.Map.empty[String, Int] withDefaultValue 0
keys foreach (k => freq(k) += 1)
val ord = Ordering by freq
keys.distinct.sorted(ord.reverse)
Nothing wrong with that implementation that comments can't fix!
Seriously, break it down a bit and describe what & why you're taking each step.
Not as "concise" perhaps, but the purpose of concise code in scala is to make code more readable. When concise code is not clear it's time to back up, break up (introduce well named local variables), and comment.
Here's my take, don't know if it's less "ugly":
scala> keys.groupBy(p => p).values.toList.sortBy(_.size).reverse.map(_.head)
res39: List[String] = List(a, b, c)
fold version:
val keys = List("c","a","b","b","a","a")
val keysCounts =
(Map.empty[String, Int] /: keys) { case (counts, k) =>
counts updated (k, (counts getOrElse (k, 0)) + 1)
}
keysCounts.toList sortBy { case (_, count) => -count } map { case (w, _) => w }
Perhaps,
val mapCount = keys.map(x => (x,keys.count(_ == x))).distinct
// mapCount : List[(java.lang.String, Int)] = List((c,1), (a,3), (b,2))
val sortedList = mapCount.sortWith(_._2 > _._2).map(_._1)
// sortedList : List[java.lang.String] = List(a, b, c)
How about:
keys.distinct.sorted
Newbie didn't read the question carefully. Let me try again:
keys.foldLeft (Map[String,Int]()) { (counts, elem) => counts + (elem -> (counts.getOrElse(elem, 0) - 1))}
.toList.sortBy(_._2).map(_._1)
Could use a mutable Map if you prefer. Negative frequency counts are stored in the map. If that bothers you, you can make them positive and negate the sortBy argument.
Just a little change from #Daniel 's 4th version, may have a better performance:
scala> def sortByFreq[T](xs: List[T]): List[T] = {
| val freq = collection.mutable.Map.empty[T, Int] withDefaultValue 0
| xs foreach (k => freq(k) -= 1)
| xs.distinct sortBy freq
| }
sortByFreq: [T](xs: List[T])List[T]
scala> sortByFreq(keys)
res2: List[String] = List(a, b, c)
My prefered versions would be:
Most canonical / expressive?
keys.groupBy(identity).toList.map{ case (k,v) => (-v.size,k) }.sorted.map(_._2)
Shortest and probably most efficient?
keys.groupBy(identity).toList.sortBy(-_._2.size).map(_._1)
Straight forward
keys.groupBy(identity).values.toList.sortBy(-_.size).map(_.head)

arbitrary size tuple with first element type fixed

Say I have two lists
val L1 = List[(Int, Int)]((1,1), (2,2))
val L2 = List[(Int, Int, Int)]((1,1,1), (2,2,2))
Now I want to make a function func that takes in an Int value i and all items from both lists where the first element matches i. One way is
def func(i:Int) = {
L1.collect.collect{case any if any._1 != i => any}
L2.collect.collect{case any if any._1 != i => any}
}
considering that the two lines are so similar, it would be nice if code can be shortened. I am thinnking of some way where I could pass L1 (and L2) as a parameter to func. The function should not know in advance how many elements the tuple will have, just that the first element is Int.
Is this possible?
[EDIT: I think the question was not clear enough. My apologies.]
Here is what I want to do. I would like to do this on more than two lists, say n, by calling func several times, once for each list.
L1 = L1.collect.collect{case any if any._1 != i => any}
L2 = L2.collect.collect{case any if any._1 != i => any}
...
Ln = Ln.collect.collect{case any if any._1 != i => any}
where each L1, L2, ... Ln are lists of tuples with first element Int
[EDIT2]
In the above, L1 could be list of (Int, String), L2 could be of (Int, Int, Int), etc. The only guarantee is that the first element is Int.
def func(i:Int, lst: List[Product]) = {
lst.filter(_.productElement(0) == i)
}
Edited as per your edit & Dan's comment above.
Any Tuple (or, indeed, any case class) is a Product, so you can use the product iterator as a way to handle tuples of indeterminate size:
val x = (1,1,1,1)
x.productIterator forall {_ == 1} //returns true
as Product is a common supertype for the elements of both lists, you can simply concatenate them and filter:
val list1 = List((1,1), (2,2))
val list2 = List((1,1,1), (2,2,2))
(list1 ::: list2) filter {_.productIterator forall {_ == 1}}
//returns List[Product with Serializable] = List((1,1), (1,1,1))
UPDATE
To filter just a single list on the first element of contained products:
val list1 = List((1,1), (2,2))
list1 filter {_.productIterator.next() == 1}