Index of List in Scala - scala

I'm new in Scala.
For example, I have a List like
val s = List(5, 11, 15, 7)
and I need a lambda function to create a new list of the indexes of the elements that are more than 10. I can not use the language Scala libraries or functions. Only standard Scala opportunities.
How can I calculate the indices of these elements? Thank you!

Try this code:
val lambda = (list: List[Int]) => {
def filterList(l : List[Int], condition : Int, index: Int, acc: List[(Int, Int)]) : List[(Int, Int)] = l match {
case List() => acc
case h::tail =>
if (h > condition) filterList( tail, condition, index + 1, (index, h) :: acc )
else filterList( tail, condition, index + 1, acc )
}
filterList(list, 10, 0, List() )
}
val r = lambda( s )

Well... there are may ways to solve this.
First lets see the more wide-spread "imperative"-like solution with var,
val lambda = (list: List[Int]) => {
var indexList = List.empty[Int]
var i = 0
for (elem <- list) {
if (elem > 10) indexList = i +: indexList
i = i + 1
}
indexList.reverse
}
Now... we can look at a bit more "functional-like" recursive approach,
val lambda = (list: List[Int]) => {
def _inner(list: List[Int], index: Int, indexList: List[Int]) = {
list match {
case Nil => indexList
case elem :: tail => {
if (elem > 10) _inner(tail, index + 1, index +: indexList)
else _inner(tail, index + 1, indexList)
}
}
}
_inner(list, 0, List.empty[Int]).reverse
}

Related

how to get the index of the duplicate pair in the a list using scala

I have a Scala list below :
val numList = List(1,2,3,4,5,1,2)
I want to get index of the same element pair in the list. The output should look like (0,5),(1,6)
How can I achieve using map?
def catchDuplicates(num : List[Int]) : (Int , Int) = {
val count = 0;
val emptyMap: HashMap[Int, Int] = HashMap.empty[Int, Int]
for (i <- num)
if (emptyMap.contains(i)) {
emptyMap.put(i, (emptyMap.get(i)) + 1) }
else {
emptyMap.put(i, 1)
}
}
Let's make the challenge a little more interesting.
val numList = List(1,2,3,4,5,1,2,1)
Now the result should be something like (0, 5, 7),(1, 6), which makes it pretty clear that returning one or more tuples is not going to be feasible. Returning a List of List[Int] would make much more sense.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.zipWithIndex //List[(Int,Int)]
.groupMap(_._1)(_._2) //Map[Int,List[Int]]
.values //Iterable[List[Int]]
.filter(_.lengthIs > 1)
.toList //List[List[Int]]
You might also add a .view in order to minimize the number of traversals and intermediate collections created.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.view
.zipWithIndex
.groupMap(_._1)(_._2)
.collect{case (_,vs) if vs.sizeIs > 1 => vs.toList}
.toList
How can I achieve using map?
You can't.
Because you only want to return the indexes of the elements that appear twice; which is a very different kind of transformation than the one that map expects.
You can use foldLeft thought.
object catchDuplicates {
final case class Result[A](elem: A, firstIdx: Int, secondIdx: Int)
private final case class State[A](seenElements: Map[A, Int], duplicates: List[Result[A]]) {
def next(elem: A, idx: Int): State[A] =
seenElements.get(key = elem).fold(
ifEmpty = this.copy(seenElements = this.seenElements + (elem -> idx))
) { firstIdx =>
State(
seenElements = this.seenElements.removed(key = elem),
duplicates = Result(elem, firstIdx, secondIdx = idx) :: this.duplicates
)
}
}
private object State {
def initial[A]: State[A] =
State(
seenElements = Map.empty,
duplicates = List.empty
)
}
def apply[A](data: List[A]): List[Result[A]] =
data.iterator.zipWithIndex.foldLeft(State.initial[A]) {
case (acc, (elem, idx)) =>
acc.next(elem, idx)
}.duplicates // You may add a reverse here if order is important.
}
Which can be used like this:
val numList = List(1,2,3,4,5,1,2)
val result = catchDuplicates(numList)
// result: List[Result] = List(Result(2,1,6), Result(1,0,5))
You can see the code running here.
I think returning tuple is not a good option instead you should try Map like -
object FindIndexOfDupElement extends App {
val numList = List(1, 2, 3, 4, 5, 1, 2)
#tailrec
def findIndex(elems: List[Int], res: Map[Int, List[Int]] = Map.empty, index: Int = 0): Map[Int, List[Int]] = {
elems match {
case head :: rest =>
if (res.get(head).isEmpty) {
findIndex(rest, res ++ Map(head -> (index :: Nil)), index + 1)
} else {
val updatedMap: Map[Int, List[Int]] = res.map {
case (key, indexes) if key == head => (key, (indexes :+ index))
case (key, indexes) => (key, indexes)
}
findIndex(rest, updatedMap, index + 1)
}
case _ => res
}
}
println(findIndex(numList).filter(x => x._2.size > 1))
}
you can clearly see the number(key) and respective index in the map -
HashMap(1 -> List(0, 5), 2 -> List(1, 6))

How immediatly return accumulator from foldLeft [duplicate]

This question already has answers here:
Scala foldLeft while some conditions are true
(6 answers)
Closed 2 years ago.
How optimize following code in good, functional way?
List(1,2,3,4,5).foldLeft(0) {
case (acc, e) =>
if(acc > 5) acc
else acc + e
}
It is of course simple example, I am asking for general way, how do not iterate all collection if we known that accumulator will not change
You can consider using #tailrec instead of foldLeft:
import scala.annotation.tailrec
#tailrec
def methodOption1(values: List[Int])(acc: Int): Int = {
if(acc > 5 || values.isEmpty) acc
else method(values.tail)(acc + values.head)
}
#tailrec
def methodOption2(values: List[Int])(sum: Int): Int = {
values match {
case Nil => sum
case _ if sum > 5 => sum
case e :: tail => method(tail)(sum + e)
}
}
methodOption1(List(1, 2, 3, 4, 5))(0)
methodOption2(List(1, 2, 3, 4, 5))(0)
You also can make Mapper to "view" it as .foldLeft
implicit class ListMapper[A](xs: List[A]) {
def foldLeftAsTailRecWithStop[B](z: B)(op: (B, A) => B)(stop: B => Boolean): B = {
#tailrec
def tailrec(xs: List[A])(acc: B): B = {
if(xs.isEmpty || stop(acc)) acc
else tailrec(xs.tail)(op(acc, xs.head))
}
tailrec(xs)(z)
}
def foldLeftAsTailRec[B](z: B)(op: (B, A) => B): B = {
#tailrec
def tailrec(xs: List[A])(acc: B): B = {
if(xs.isEmpty) acc
else tailrec(xs.tail)(op(acc, xs.head))
}
tailrec(xs)(z)
}
}
List(1, 2, 3,4,5).foldLeft(0)(_ + _)
List(1, 2, 3,4,5).foldLeftAsTailRec(0)(_ + _)
List(1, 2, 3,4,5).foldLeftAsTailRecWithStop(0)(_ + _)(_ > 5)
Outputs:
res0: Int = 15
res1: Int = 15
res2: Int = 6
You can use scanLeft(produces a lazy list containing cumulative results of applying the operator going left to right, including the initial value) and find (finds the first element of the lazy list satisfying a predicate, if any):
List(1,2,3,4,5)
.to(LazyList)
.scanLeft(0)(_ + _)
.find(_ > 5) // Some(6): Option[Int]
UPD
To tackle the issue raised by #jwvh in the comments I was able to come up only with this ugly design:
List(1,2,3,4,5)
.to(LazyList)
.scanLeft((0, 0))((t, c) => (t._1 + c, t._1)) // aggregate contains current and previous value
.takeWhile(t => (t._1 > 5 && t._2 <= 5) || t._1 <= 5)
.last._1
So I would say that writing custom tailrec function as in #Zvi Mints's answer should be a better option here.

Why is Scala returning a ';' expected but ',' found error?

I am currently trying to write an inversion count algorithm in Scala, utilizing a working merge-sort algorithm.
The merge-sort functions as expected but when I try to add a count as one of the parameters I get back the error:
Error:(14, 29) ';' expected but ',' found.
case (_, Nil) => left, count
^
Here is the program:
object MergeSort {
def mergeSort(inputList: List[Int]): List[Int] = {
if (inputList.length <= 1) inputList
else {
val (left, right) = inputList.splitAt(inputList.size / 2)
merge(mergeSort(left), mergeSort(right), 0)
}
}
def merge(left: List[Int], right: List[Int], count: Int): List[Int] =
(left, right) match {
case (_, Nil) => left, count
case (Nil, _) => right, count
case (leftHead :: leftTail, rightHead :: rightTail) =>
if (leftHead < rightHead){
val (leftList, leftCount) = leftHead :: merge(leftTail, right, count)
return (leftList, leftCount)
}
else {
val (rightList, rightCount) = rightHead :: merge(left, rightTail, count)
val mergeInversions = leftCount + left.length
return (rightList, mergeInversions)
}
}
val inputList: List[Int] = List(10, 3, 5, 1, 7, 6)
val sorted_arr = mergeSort(inputList)
}
#sepp2k pointed out correctly in the comment that if you want to create a tuple, then you need to wrap it around parentheses.
Here's the working solution:
object MergeSort {
def mergeSort(inputList: List[Int]): List[Int] = {
if (inputList.length <= 1) inputList
else {
val (left, right) = inputList.splitAt(inputList.size / 2)
merge(mergeSort(left), mergeSort(right), 0)._1
}
}
def merge(left: List[Int], right: List[Int], count: Int): (List[Int], Int) =
(left, right) match {
case (_, Nil) => (left, count)
case (Nil, _) => (right, count)
case (leftHead :: leftTail, rightHead :: rightTail) =>
if (leftHead < rightHead) {
val left = merge(leftTail, right, count)
val (leftList, leftCount) = (leftHead :: left._1, left._2)
(leftList, leftCount)
} else {
val right = merge(left, rightTail, count)
val (rightList, rightCount) = (rightHead :: right._1, right._2)
val mergeInversions = rightCount + left.length
(rightList, mergeInversions)
}
}
val inputList: List[Int] = List(10, 3, 5, 1, 7, 6, 0)
val sorted_arr = mergeSort(inputList)
}

What is the efficient way to remove subsets from a List[List[String]]?

I have a ListBuffer of List[String], val tList = ListBuffer[TCount] where TCount is case class TCount(l: List[String], c: Long). I want to find those list l from tList which are not the subset of any other element of tlist and their c value is less than their superset c value. The following program works but I have to use two for loop that makes the code inefficient. Is there any better approach I can use to make the code efficient?
val _arr = tList.toArray
for (i <- 0 to (_arr.length - 1)) {
val il = _arr(i).l.toSet
val ic = _arr(i).c
for (j <- 0 to (_arr.length - 1)) {
val jl = _arr(j).toSet
val jc = _arr(j).c
if (i != j && il.subsetOf(jl) && ic >= jc) {
tList.-=(_arr(i))
}
}
}
Inspired by the set-trie comment:
import scala.collection.SortedMap
class SetTrie[A](val flag: Boolean, val children: SortedMap[A, SetTrie[A]])(implicit val ord: Ordering[A]) {
def insert(xs: List[A]): SetTrie[A] = xs match {
case Nil => new SetTrie(true, children)
case a :: rest => {
val current = children.getOrElse(a, new SetTrie[A](false, SortedMap.empty))
val inserted = current.insert(rest)
new SetTrie(flag, children + (a -> inserted))
}
}
def containsSuperset(xs: List[A], strict: Boolean): Boolean = xs match {
case Nil => !children.isEmpty || (!strict && flag)
case a :: rest => {
children.get(a).map(_.containsSuperset(rest, strict)).getOrElse(false) ||
children.takeWhile(x => ord.lt(x._1, a)).exists(_._2.containsSuperset(xs, false))
}
}
}
def removeSubsets[A : Ordering](xss: List[List[A]]): List[List[A]] = {
val sorted = xss.map(_.sorted)
val setTrie = sorted.foldLeft(new SetTrie[A](false, SortedMap.empty)) { case (st, xs) => st.insert(xs) }
sorted.filterNot(xs => setTrie.containsSuperset(xs, true))
}
Here is a method that relies on a data structure somewhat similar to Set-Trie, but which stores more subsets explicitly. It provides worse compression, but is faster during lookup:
def findMaximal(lists: List[List[String]]): List[List[String]] = {
import collection.mutable.HashMap
class Node(
var isSubset: Boolean = false,
val children: HashMap[String, Node] = HashMap.empty
) {
def insert(xs: List[String], isSubs: Boolean): Unit = if (xs.isEmpty) {
isSubset |= isSubs
} else {
var isSubsSubs = false || isSubs
for (h :: t <- xs.tails) {
children.getOrElseUpdate(h, new Node()).insert(t, isSubsSubs)
isSubsSubs = true
}
}
def isMaximal(xs: List[String]): Boolean = xs match {
case Nil => children.isEmpty && !isSubset
case h :: t => children(h).isMaximal(t)
}
override def toString: String = {
if (children.isEmpty) "#"
else children.flatMap{
case (k,v) => {
if (v.children.isEmpty) List(k)
else (k + ":") :: v.toString.split("\n").map(" " + _).toList
}
}.mkString("\n")
}
}
val listsWithSorted = for (x <- lists) yield (x, x.sorted)
val root = new Node()
for ((x, s) <- listsWithSorted) root.insert(s, false)
// println(root)
for ((x, s) <- listsWithSorted; if root.isMaximal(s)) yield x
}
Note that I'm allowed to do any kind of mutable nonsense inside the body of the method, because the mutable trie data structure never escapes the scope of the method, and can therefore not be inadvertently shared with another thread.
Here is an example with sets of characters (converted to lists of strings):
println(findMaximal(List(
"ab", "abc", "ac", "abd",
"ade", "efd", "adf", "bafd",
"abd", "fda", "dba", "dbe"
).map(_.toList.map(_.toString))))
The output is:
List(
List(a, b, c),
List(a, d, e),
List(e, f, d),
List(b, a, f, d),
List(d, b, e)
)
so indeed, the non-maximal elements ab, ac, abd, adf, fda and dba are eliminated.
And here is what my not-quite-set-trie data structure looks like (child nodes are indented):
e:
f
b:
e
d:
e
f
c
f
d:
e:
f
f
a:
e
b:
d:
f
c
f
d:
e
f
c
f
c
f
Not sure if you can avoid the complexity, but, I guess I'd write like this:
val tList = List(List(1, 2, 3), List(3, 2, 1), List(9, 4, 7), List(3, 5, 6), List(1, 5, 6), List(6, 1, 5))
val tSet = tList.map(_.toSet)
def result = tSet.filterNot { sub => tSet.count(_.subsetOf(sub)) > 1 }
Here's one approach:
Create an indexed Map for identifying the original List elements
Turn Map of List-elements into Map of Sets (with index)
Generate combinations of the Map elements and use a custom filter to capture the elements that are subset of others
Remove those subset elements from the Map of Sets and retrieve remaining elements from the Map of Lists via the index
Sample code:
type TupIntSet = Tuple2[Int, Set[Int]]
def subsetFilter(ls: List[TupIntSet]): List[TupIntSet] =
if ( ls.size != 2 ) List.empty[TupIntSet] else
if ( ls(0)._2 subsetOf ls(1)._2 ) List[TupIntSet]((ls(0)._1, ls(0)._2)) else
if ( ls(1)._2 subsetOf ls(0)._2 ) List[TupIntSet]((ls(1)._1, ls(1)._2)) else
List.empty[TupIntSet]
val tList = List(List(1,2), List(1,2,3), List(3,4,5), List(5,4,3), List(2,3,4), List(6,7))
val listMap = (Stream from 1).zip(tList).toMap
val setMap = listMap.map{ case (i, l) => (i, l.toSet) }
val tSubsets = setMap.toList.combinations(2).toSet.flatMap(subsetFilter)
val resultList = (setMap.toSet -- tSubsets).map(_._1).map(listMap.getOrElse(_, ""))
// resultList: scala.collection.immutable.Set[java.io.Serializable] =
// Set(List(5, 4, 3), List(2, 3, 4), List(6, 7), List(1, 2, 3))

Use a Scala collection method to help convert a list of [0,0,0,1,1,1,1,0,0,1,1] into [3,4,2,2]

So I have a list of 0's and 1's, I want to find the count of each element and output this to a list. I can think of a recursive way to do it with functions but is there any helper functions which can help to convert this?
I believe groupBy could be useful but it seems to group all the elements into one partition or another, not into the way I want.
I want to have a list of the count of numbers until each transition from 0 to 1 and 1 to 0. ie, if we have 0,0,0, .. ok we counted 3 zeros so remember 3, then we have 1,1,1,1 so we counted 4 1's, so we remember 4, so far we have a list of [3,4...] and so on
tail-rec version of Yann Moisan's solution:
def pack[A](ls: Seq[A], prev: Seq[Int] = Seq.empty): Seq[Int] = {
if (ls.isEmpty) prev
else {
val (packed, next) = ls span {_ == ls.head }
pack(next, prev :+ packed.size)
}
}
def pack[A](ls: List[A]): List[Int] = {
if (ls.isEmpty) List(0)
else {
val (packed, next) = ls span { _ == ls.head }
if (next == Nil) List(packed.size)
else packed.size :: pack(next)
}
}
This might be a little complicated. but I'd go with it.
scala> implicit class ListHelper[A](ls:List[A]) {
def partitionBy(f: (A, A) => Boolean) = if (ls.isEmpty) List.empty[Int]
else (ls zip (ls.head :: ls)).foldLeft(List.empty[Int]){
case (Nil, _) => List(1)
case (x :: xs, (a, b)) => if (a == b) (x + 1) :: xs else 1 :: x :: xs
}.reverse
}
defined class ListHelper
scala> List(0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1).partitionBy(_ == _)
res27: List[Int] = List(3, 4, 2, 2)
This is based on the clojure function partition-by
This is groupBy.
val tuple = list.foldRight((0,0)) { (x, accum) =>
if (x == 0) (accum._1 +1, accum._2) else (accum._1, accum._2 +1)
}
List(tuple._1, tuple._2)
on similar lines here is fliptracker (for non-empty lists):
def fliptracker(list: List[Int]) = {
val initial = (list.head, 0, List.empty[Int])
val result = list.foldLeft(initial) {
(acc, x) =>
if (acc._1 == x) (acc._1, acc._2 + 1, acc._3)
else (x, 1, acc._3 ::: List(acc._2))
}
result._3 ::: List (result._2)
}
fliptracker(List(0,0,0,1,1,1,1,0,0,1,1)) // List(3, 4, 2, 2)
I would do
List(0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1).foldLeft (List.empty[(Any,Int)]) {
(acc,a) => acc match {
case (`a`, occ) :: tail => (a,occ+1) :: tail
case _ => (a,1) :: acc
}}.reverse.map(_._2)
res1: List[Int] = List(3, 4, 2, 2)
Another alternative answer based upon takeWhile. In this 1==black and 0==white
case class IndexCount(index: Int, count: Int, black: Boolean)
#tailrec
def takeWhileSwitch(black: Boolean, index:Int, list: List[Boolean],
result: List[IndexCount]): List[IndexCount] = {
if (list == Nil) return result.reverse
val takenWhile = list.takeWhile(black == _)
val takenLength = takenWhile.length
val resultToBuild = if (takenLength != 0) {
val indexCount = IndexCount(index, takenLength, black)
indexCount :: result
} else result
takeWhileSwitch(!black, index + takenLength, list.drop(takenLength), resultToBuild)
}
val items = takeWhileSwitch(true, 0, rowsWithBlack, List[IndexCount]())
Nobody expects the imperative solution:
def chunk[A](xs: List[A]) = {
val ys = collection.mutable.Buffer[Int]()
var prev = xs.head
var count = 1
for (x <- xs.tail) {
if (x != prev) {
ys += count
prev = x
count = 1
}
else count += 1
}
ys += count
ys.toList
}