Scala list of list count different elements per sublist index - list

I have a list of lists with the following data
val list = List(List("a","b","c"),List("d","e","f"),List("a","a","a"))
I want to disicover how many different data do I have in each position of the sublists
1 -> List("a","d","a")
2 -> List("b","e","a")
3 -> List("c","f","a")
Is there a way to do that? It doesn't need to be indexed, but I need the amount of different values per sublist index, the result could also be
2 // different values a and d
3 // different values b, e and a
3 // different values c, f and a

As I noted in a comment on Jhonny Everson's (almost right but now deleted) answer, you can use transpose to get a list of the columns, and then distinct to remove duplicates:
scala> list.transpose.map(_.distinct.size)
res0: List[Int] = List(2, 3, 3)
This will throw an exception if all the lists don't have the same size, but that's probably what you want.

scala> list.transpose.map(_.toSet.size)
res0: List[Int] = List(2, 3, 3)
The output of list.transpose is List(List(a, d, a), List(b, e, a), List(c, f, a)) which gives you the structure you want then map each List to a Set to get the unique elements and count them.
If you want unique elements per position, then you can use zipWithIndex and reverse the outputs.
scala> list.transpose.map(_.distinct).zipWithIndex.map(t => t._2 -> t._1)
res1: List[(Int, List[String])] = List((0,List(a, d)), (1,List(b, e, a)), (2,List(c, f, a)))

Here is the code you wanted:
var lOfl = List(List.range(1,5), List(2,2,2,3), Nil)
//> lOfl : List[List[Int]] = List(List(1, 2, 3, 4), List(2, 2, 2, 3), List())
for {
l <- lOfl
} yield l.toSet.count(_ => true) //> res1: List[Int] = List(4, 2, 0)
A sample list of list of Int is created as lOfl; for loop iterates through each list of Int; toSet converts list to set eliminating duplicate elements. then count function does as the name says it all.
OR use the Scala's most used collection function (:P :P), map, like below,
lOfl.map(l => l.toSet.count(_ => true) ) //> res2: List[Int] = List(4, 2, 0)

Related

How to merge two types of for comprehension in Scala?

I have seen for being used different ways in Scala, to take some value out of a wrapper like Option or on list or other collections. If I have to pull a List[Int] out of an Option and then iterate on it, can this be done in one for block?
eg.
val l: Option[List[Int]] = Some(List(1,2,3,4))
l: Option[List[Int]] = Some(List(1, 2, 3, 4))
for{
li <- l // li taken out from Option wrapper
number <- li // numbers pulled from li
} yield number*2
cmd7.scala:3: type mismatch;
found : List[Int]
required: Option[?]
number <- li
^
If I understand correctly it wants each entry to be an Option. Is there some way to achieve this effect without two for loops?
Is there some way to achieve this effect without two for loops?
You can do this by calling toList on the Option[List[Int]], turning it into a List[List[Int]] which the for comprehension will flatMap over:
for {
| o <- l.toList
| num <- o
| } yield num * 2
res8: List[Int] = List(2, 4, 6, 8)
This will yield an empty list for the None type:
scala> val l: Option[List[Int]] = None
scala> for {
| o <- l.toList
| num <- o
| } yield num * 2
res3: List[Int] = List()
You can also use Option[T].getOrElse with an empty List[T] as fallback if the option is empty:
scala> for {
| o <- l.getOrElse(List())
| } yield o * 2
res13: List[Int] = List(2, 4, 6, 8)
Personally, I like the explicit map call:
scala> l.map(_.map(_ * 2))
res7: Option[List[Int]] = Some(List(2, 4, 6, 8))
For comprehensions expand to flatMaps, maps and lazy version of filter. flatMap for Option does not accept function A => List[A]. In general you can use only one type of monad in for comprehension.
Obvious solution here are monad transformers. If you have two monads, one in another, it allows you to access the values inside the deeper monad by creating another monad that combines behavior of two.
Note that this works for any two monads, not just Option and List.
Using scalaz:
import scalaz._
import Scalaz._
val list: Option[List[Int]] = Some(List(1, 2, 3, 4))
(for {
number <- ListT(list)
} yield number * 2).run
res0: Option[List[Int]] = Some(List(2, 4, 6, 8))
You need to call run to unwrap the value from transformer.
you can then use more than one list like this:
val xs = List(1, 2, 3).some
val ys = List(0, 2).some
(for {
x <- ListT(xs)
y <- ListT(ys)
} yield x * y).run
res0: Option[List[Int]] = Some(List(0, 2, 0, 4, 0, 6))
If any Option would be None the result would be None as well
(for {
x <- ListT(xs)
y <- ListT(ys)
z <- ListT(none[List[Int]])
} yield x * y).run
res0: Option[List[Int]] = None

How to sort a List of Lists of pairs of number in descending order by the second item in each pair in Scala?

I have a list that looks like this List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))), note this list will only contain pairs and will not contain duplicate pairs. I want to sort the list in descending order by the second item in each sub list in this larger list. If there are duplicate values I don't really which comes first.
For this instance the answer could look like List(List(0,3), List(2,3), List(0,2), List(3,2), List(3,0), List(2,0))
My idea was looping through the larger list and get a list containing each second item in each pair and sort those but I am having trouble keeping track of which second item in each pair belong to which pair afterwards. Perhaps there is a more clever way?
A simple solution would be:
list.sortBy(-_.last)
You can simply do:
list.sortBy(-_(1))
If the lists are always length 2, I would use tuples instead of lists. Then it is just a matter of using sortBy
scala> val l1 = List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))
l1: List[List[Int]] = List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))
scala> val l2 = l1.map(x => (x(0), x(1)))
l2: List[(Int, Int)] = List((0,2), (0,3), (2,3), (3,2), (3,0), (2,0))
scala> l2.sortBy(-_._2)
res1: List[(Int, Int)] = List((0,3), (2,3), (0,2), (3,2), (3,0), (2,0))
list.sortBy( sublist => -1 * sublist.tail.head )

Duplicate list elements which based on predicate

I would like to duplicate even/odd elements in a list.
def even(number: Int): Boolean = {
if(number%2 == 0) true
else false
}
I tried something weird cause i have no idea how should I do that exactly.
scala> var x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.map(el => if(even(el)) el::x)
res143: List[Any] = List((), List(2, 1, 2, 3), ())
This is not what I expected. I'd like to return only one list with all elements where odd/even are duplicated.
Thanks for your help.
You can use flatMap to return a list per element, either containing just the element itself if the predicate doesn't match, or a list with the element duplicated if it does:
def even(n : Int) : Boolean = n%2 == 0
val l = List(1,2,3)
l.flatMap(n => if(even(n)) List(n,n) else List(n)) // -> List(1, 2, 2, 3)
You can filter the first collection for even numbers, and than concat with the original list:
scala> var l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> l.filter(_ % 2 == 0) ++ l
res14: List[Int] = List(2, 1, 2, 3)
If you want the List[Int] sorted, you can apply that after the concatenation:
scala> l.filter(_ % 2 == 0) ++ l sorted
res15: List[Int] = List(1, 2, 2, 3)
This saves you the allocation of a new List[Int] for every match of even. You filter only the elements you need, creating one List[Int], and then concatenating it with the original.

scala build a dictionary from a list and a function

I have a scala list and a funcion:
val l = List((1,2), (3,4), (5,6))
def f(x:Int, y:Int) = x+y
I want to build a dictionary that associated to each tuple its sum.
The result f(1,2) should be kept in memory and not recomputed each time that it is called. How can I do that? In python I would use a dictionary.
l.map(x => x -> (f _).tupled(x)).toMap
An analog to Python dictionaries in Scala is Map:
λ val resultsMap = Map( // Create a map from a Seq of (key, value) pairs
l.zip( // List(((1, 2), SOMETHING), ((3, 4), SOMETHING), etc.)
l.map((f _).tupled) // Invoke `f` on each entry in `l`
).toSeq : _*)
resultsMap: Map[(Int, Int), Int] = Map((1, 2) -> 3, (3, 4) -> 7, (5, 6) -> 11)
Usage:
λ resultsMap((1, 2))
res0: Int = 3
Using a for comprehension we can extract the tuple values as well as bind each tuple for constructing the associations, like this,
for ( t#(a,b) <- l ) yield t -> f(a,b)
Thus applying toMap on the collection from the comprehension we get the desired map. In this approach though we must declare as many items in the tuple as we wish to be applied to the function.

Scala - select elements from ordered list

I am looking for a nice way to remove first N elements which are equal from the ordered list, e.g.
List(1,1,1,2,3,3)
should return
removeSame(list) -> (1,1,1)
Is there a nice way to do it, rather than remove the head of the list and then use takeWhile on the remainder, and finally using dropwhile? I can think of simple non-functional solution but I was wondering whether any functional one also exists
The functional way to avoid the duplication of takeWhile and dropWhile to get a prefix and remainder is using span, i.e.
scala> val list = List(1,1,1,2,3,3)
list: List[Int] = List(1, 1, 1, 2, 3, 3)
scala> val (prefix, rest) = list span (_ == list.head)
prefix: List[Int] = List(1, 1, 1)
rest: List[Int] = List(2, 3, 3)
Is this what you look for?
scala> val l = List(1,1,1,2,3,3)
l: List[Int] = List(1, 1, 1, 2, 3, 3)
scala> l.takeWhile(_ == l.head)
res6: List[Int] = List(1, 1, 1)
scala> val l = List()
l: List[Nothing] = List()
scala> l.takeWhile(_ == l.head)
res7: List[Nothing] = List()
Not the best way of doing it, but this also works:
def removeSame(l: List) = if( !l.isEmpty) l.groupBy( x => x)(l.head) else List()