14

Hi I have a map like this :

[this:0, is:1, a:2, file:3, anotherkey:4, aa:5]

I wish I could find the key's given the value of a map. For example, if the value 5 is given I need to return aa from the map.

Is that possible?

lucke84
  • 4,516
  • 3
  • 37
  • 58
sriram
  • 8,562
  • 19
  • 63
  • 82

5 Answers5

19

I don't know if there's a direct method to get a key for a given value, but using Map#find to get a map entry and then get its value should be enough:

def keyForValue(map, value) {
    map.find { it.value == value }?.key
}

def map = [a: 1, b: 2, c: 3]
assert keyForValue(map, 2) == 'b'
assert keyForValue(map, 42) == null

In general, maps don't need to have an order relation between their entries, but the default implementation for Groovy's literal maps is LinkedHashMap, which is ordered, so the keyForValue will always yield the first key for a value when using those maps.

epidemian
  • 18,817
  • 3
  • 62
  • 71
10

There's no specific command for that.

Fortunately, as showed here, you can easily get the key(s) for a specific value in a map:

def myMap = [this:0, is:1, a:2, file:3, fix:4, aa:5]
def myValue = 5

You can do:

def myKey = myMap.find{ it.value == myValue }?.key
// 'aa'

If you want all the keys, do something like this:

def myMap = [this:0, is:1, a:2, file:3, fix:4, aa:5, bb:5]
def myValue = 5

def myKeys = []
myMap.findAll{ it.value == myValue }.each{myKeys << it?.key}
// ['aa', 'bb']
lucke84
  • 4,516
  • 3
  • 37
  • 58
3

You could invert the map, like this:

Map m = [a: '1', b: '2']
Map mInvert = m.collectEntries { e -> [(e.value): e.key] }

assert mInvert == ['1':'a', '2':'b']

assert mInvert['2'] == 'b'
assert m['b'] == '2'
crazy4groovy
  • 125
  • 1
  • 5
  • No, your code is interesting :) but performance killer because you recreate another Map. There is a method to find a Map entry given it's value, the correct answer has been given by epidemian long time ago : myMap.find{ it.value == 5 }.key – ARA Aug 03 '16 at 16:02
  • 1
    @ARA actually for repeated use crazy4groovy's solution will be faster as long as the inverted collection is not recreated every time. You should not iterate over a list O(n) when you can use a map at O(logN). Of course, performance should take a back-seat to readability anyway--and if done right crazy4groovy's solution is probably more readable too... However it isn't terribly "Groovy" :) – Bill K Jun 09 '17 at 17:36
  • @Bill : Yes, what I said is performance killer is to recreate the map each time like the example who uses a lambda to recreate it on the fly. Of course if the map is not recreated on each call and maintained, this would be much much faster than iterating. That's the purpose of a Map. :) And I think Map is said to be O(1) not O(log(n)), a btree would be O(log(n)) ? – ARA Jun 10 '17 at 03:47
1

You'll probably have to iterate over the entry set yourself and try to find the entry with a matching value.

JimmyB
  • 12,101
  • 2
  • 28
  • 44
1
def expect = 5
def m = ['this':0, is:1, a:2, file:3,  aa:5]
def r = m.collectMany{ k,v -> (v == expect) ? [k] : []}

// Result: [aa]