KajMagnus
KajMagnus

Reputation: 11666

Can I removeWhile from a LinkedHashMap?

How do I remove the oldest entries from a LinkedHashMap without traversing the whole map or collecting keys in an intermediate collection? LinkedHashMap entries are sorted by insertion order, so the oldest are found first when iterating. I'd like to do this:

  userAndWhenMap.iterator.removeWhile { case (userId, userAndWhen) =>
    now.millisSince(userAndWhen.when) > DeleteAfterInactiveMillis
  }

But removeWhile doesn't exist. There's a dropWhile but it doesn't mutate the map — it advances an iterator. Is there no way to achieve something like removeWhile?

(I know about retain but it traverses the whole map. And I know I can find the keys I want to remove and insert them in a set and then loop through it and Map.remove(..).)

Upvotes: 0

Views: 57

Answers (1)

Łukasz
Łukasz

Reputation: 8663

I think the only way is to implement your removeWhile method as an extension method for LinkedHashMap class

There are only two methods that modify the this collection instead of returning new: retain and transform (I am ignoring ++=, +=, --= and -= here) and they don't do what you need.

here is example code:

implicit class LinkedHashMapOps[A, B](val self: LinkedHashMap[A, B]) extends AnyVal {
  def removeWhile(predicate: ((A, B)) => Boolean): self.type = {
    val toRemove = self.iterator.takeWhile(predicate).map(_._1)
    toRemove foreach (self -= _)
    self
  }
}

and test:

@ val map = new LinkedHashMap[Int, String]
@ map += (1 -> "a")
@ map += (2 -> "a")
@ map += (3 -> "a")
@ map += (4 -> "a")
res6: LinkedHashMap[Int, String] = Map(1 -> "a", 2 -> "a", 3 -> "a", 4 -> "a")
@ map.removeWhile(_._1 < 3)
res8: LinkedHashMap[Int, String] = Map(3 -> "a", 4 -> "a")

Upvotes: 2

Related Questions