I am trying to remove given elements for n occurences(not all occurrences!) in the list. The problem I'm facing is when I try to branch into two cases in which the list contains the given element or does not. My if statement gives me an error as descripted in the title. How can I resolve this problem?
My code
def removeN[A](xs: List[A], elem: A, n: Int) : List[A] = {
val elemCount = xs.groupBy(identity).mapValues(_.size)(elem)
if (xs.contains(elem) == false)
xs
else if (elemCount == n)
xs.filterNot(x => x == elem)
else {
val (left, right) = xs.span(_ != elem)
print(s"$left and $right")
left ::: right.tail
}
}
Error messages
removeN(List(1,2,3,2,1), 0, 2)
java.util.NoSuchElementException: key not found: 0
at scala.collection.MapOps.default(Map.scala:274)
at scala.collection.MapOps.default$(Map.scala:273)
at scala.collection.AbstractMapView.default(MapView.scala:186)
at scala.collection.MapOps.apply(Map.scala:176)
at scala.collection.MapOps.apply$(Map.scala:175)
at scala.collection.AbstractMapView.apply(MapView.scala:186)
at removeN(<console>:3)
... 32 elided
Test Case
removeN(List(1,2,3,2,1), 0, 2) // => List(1, 2, 3, 2, 1)
CodePudding user response:
It is not contains
which is throwing - you are trying to get the element from map before checking if it will be there at all:
val elemCount = xs.groupBy(identity).mapValues(_.size)(elem)
just count elements in-place:
def removeN[A](xs: List[A], elem: A, n: Int) : List[A] = {
if (xs.contains(elem) == false) xs
else if (xs.count(_ == elem) == n) xs.filterNot(x => x == elem)
else {
val (left, right) = xs.span(_ != elem)
print(s"$left and $right")
left ::: right.tail
}
}
CodePudding user response:
I guess, I am missing something, but your function (after fixing the bug mentioned in the other answer) seems to be removing all occurrences if there are exactly n
of them, or just the first occurrence otherwise (it is also very inefficient, involving multiple redundant traversals of the list).
Here is a (more efficient) version, removing first N occurrences, assuming that's what you actually were after:
def removeN[A](xs: List[A], elem: A, n: Int, result: List[A]=Nil): List[A] = xs match {
case Nil => result.reverse
case `elem`::tail if n > 0 => removeN(tail, elem, n-1 result)
case head::tail => removeN(tail, elem, n, head::result)
}
This can be marginally improved further by adding a "shortcut" special case for n==0 && result == Nil
, but doesn't seem worth the effort and loss of readability.