I'm struggling with the absence of Java's Iterator.remove()
in Scala. In particular, I want to, in a single pass over a large mutable map, remove elements that satisfy a predicate and collect them in another mutable map.
Here's what I am trying to do:
def main(args: Array[String]) {
val map = new TrieMap[String, Integer]();
map += "one" -> 1
map += "two" -> 2
// Remove all elems whose value is > 1 and put them in val removed.
val removed = removeIf(map, _._2 > 1)
}
def removeIf(
map: mutable.Map[String, Integer],
p: ((String, Integer)) => Boolean): mutable.Map[String, Integer] = {
val result = mutable.Map[String, Integer]()
val iter = map.iterator
while (iter.hasNext) {
val elem = iter.next()
if ( p(elem) ) {
iter.remove() // Error
result += elem
}
}
result
}
For some sound reason, Scala's Iterator
, even on a mutable collection, does not implement remove()
.
Edit Two solutions offered below are:
Don't worry about the cost of the second pass and use filter() and then
--=
to remove the filtered entries:val result = map.filter(p)
map --= result.keys
Use partition and reassign the new map to the old variable:
(result, newMap) = map.partition({case (k,v) => ... })
I ran some tests. As expected, first solution is actually faster, in cases when the number of removed entries is smaller compared to the size of the original map. The inflection point, where the two solutions run for roughly the same time is when the predicate splits the original map about in half. The second solution doesn't seem to depend on this, but the first one, obviously does. Both are O(n), so perhaps I am being too picky here. I wish I could split the checkmark between the two answers. Thanks to both, Don Branson and rogue-one.