What is the proper way to remove elements from a scala mutable map using a predicate
Asked Answered
G

4

15

How to do that without creating any new collections? Is there something better than this?

val m = scala.collection.mutable.Map[String, Long]("1" -> 1, "2" -> 2, "3" -> 3, "4" -> 4)
m.foreach(t => if (t._2 % 2 == 0) m.remove(t._1))
println(m)

P.S. in Scala 2.8

Gushy answered 23/3, 2010 at 14:12 Comment(4)
Questions about collections should say whether a 2.7 or a 2.8 answer is sought.Evaporimeter
Using 2.8 for quite a long time, already forgot about 2.7. Thanks, added P.S.Gushy
There's a Scala-2.8 tag you could add as an indication that this is a 2.8 specific question.Fremd
Thanks, replaced "predicate" with itGushy
M
19

retain does what you want. In 2.7:

val a = collection.mutable.Map(1->"one",2->"two",3->"three")
a: scala.collection.mutable.Map[Int,java.lang.String] = 
  Map(2 -> two, 1 -> one, 3 -> three)

scala> a.retain((k,v) => v.length < 4)   

scala> a
res0: scala.collection.mutable.Map[Int,java.lang.String] =
  Map(2 -> two, 1 -> one)

It also works, but I think is still in flux, in 2.8.

Metamer answered 23/3, 2010 at 14:36 Comment(3)
Looks like retain is deprecated in 2.8: scala-lang.org/archives/downloads/distrib/files/nightly/docs/… deprecated: cannot be type inferred because of retain in Iterable.Gushy
Indeed; they might have to rename it, or come up with some other workaround. I don't think it will just vanish; that would be kind of silly. I'm interpreting that deprecation as "in flux, might change".Metamer
Looks like deprecation is going to be removed. So the answer is correct.Gushy
S
2

Per the Scala mutable map reference page, you can remove a single element with either -= or remove, like so:

val m = scala.collection.mutable.Map[String, Long]("1" -> 1, "2" -> 2, "3" -> 3, "4" -> 4)
m -= "1" // returns m
m.remove("2") // returns Some(2)

The difference is that -= returns the original map object, while remove returns an Option containing the value corresponding to the removed key (if there was one.)

Of course, as other answers indicate, if you want to remove many elements based on a condition, you should look into retain, filter, etc.

Sisson answered 18/10, 2012 at 18:6 Comment(0)
A
0

If you are using an immutable.Map, in 2.7 it might have to be something like:

def pred(k: Int, v: String) = k % 2 == 0

m --= (m.filter(pred(_, _)).keys

As there is no retain method available. Obviously in this case m must be declared as a var

Antilebanon answered 23/3, 2010 at 16:11 Comment(2)
If you're using an immutable Map and hence must create a new one, it's pretty easy to simply filter with the negation of the predicate.Evaporimeter
Indeed, this is true: it depends what you feel is more readable in a given situationAntilebanon
L
0

for scala version=2.13.6 use filterInPlace

doc link

@ val a = collection.mutable.Map(1->"one",2->"two",3->"three")
a: collection.mutable.Map[Int, String] = HashMap(
  1 -> "one",
  2 -> "two",
  3 -> "three"
)

@ a.filterInPlace((k,v) => v.length < 4)
res1: collection.mutable.Map[Int, String] = HashMap(1 -> "one", 2 -> "two")

@ a
res2: collection.mutable.Map[Int, String] = HashMap(1 -> "one", 2 -> "two")
Lauds answered 13/9, 2022 at 14:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.