3

In a Scala Map, how do I get all keys in a Map that have the same value?

For example in my Map I have 3 keys which have the value 27

Eg:

large -> 27
indispensable -> 27
most -> 27 

I tried

val adj1value = htAdjId.find(_._2 == value1).getOrElse(default)._1

but that gives me only the first key "large" (as is the definition of find). I searched a lot but I am not able to find a "findall" function. Does it exist in Scala? If not, can someone please advice me on how to solve this problem?

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
mithunpaul
  • 3,268
  • 22
  • 19

3 Answers3

0

You can filter the collection and extract all keys using keys:

val map = Map("h" -> 27, "b" -> 2, "c" -> 27)
map.filter { case (key, value) => value == 27 }.keys

Yields

res0: Iterable[String] = Set(h, c)

Though I'd argue that if you need to iterate the entire Map each time, perhaps it isn't the right data structure to begin with, perhaps a List[(String, Int)] will suffice and save the overhead incurred by using a Map.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • I agree with the last paragraph. If lookup is always this way, then the `Map` is simply the wrong way round. (It would need to be a `Multimap` in the other direction, though.) If lookup is needed in both directions, a `BidiMap` (aka `BiMap`) or more precisely a `MultiBiMap` / `MultiBidiMap` / `BiMultiMap` / `BidiMultiMap` (or whatever it is called) would be the data structure of choice. (Actually, the data structure is a bidirectional relation, like a SQL table.) – Jörg W Mittag Jun 09 '17 at 11:53
0

You can treat the map as a Iterable[K,V] then groupBy the value like this..

@ Map(
    "large" -> 27,
    "indispensable" -> 27,
    "most" -> 27
).groupBy(_._2).mapValues(_.keys)

res4: Map[Int, Iterable[String]] = Map(27 -> Set(
  "large",
  "indispensable",
  "most"))
Stephen
  • 4,228
  • 4
  • 29
  • 40
0

[answered by a friend of mine offline] Hashmaps are usually built to do only the forward lookup efficiently. Unless you know that the underlying data structure used in the hashmap supports this, you probably don't want to do this "reverse lookup" because it will be very inefficient.

Consider putting your data into a bi-directional map or "bi-map" from the start if you are going to access it in both directions. OR, use two hashmaps: one in regular direction, one inverted (values become keys, keys become values) OR use different data structure altogether.

i.e two maps is a good idea if the map is large or you're going to be doing this kind of check a lot. Otherwise try filter instead of find

mithunpaul
  • 3,268
  • 22
  • 19
  • [I asked him] my values are not unique. So will a bi-directional map work? Shouldnt the values and keys also be unique to use guava's bimap? – mithunpaul Jun 12 '17 at 03:37
  • [his reply] Then a bi-directional map probably won’t work. If you’re just doing the reversal once, you might try groupBy, as in `val value2adj = htAdjId.groupBy{ case (k, v) => v }.map{ case (k, v) => k -> v.map(_._1) }` That would give you a map from values to a list of keys having that value, which you can then use `getOrElse` on. There’s probably even a shortcut to do this. – mithunpaul Jun 12 '17 at 03:38