Java maps, going from values to keys
Is there any way to get a key associated with a known value in a map? Normally you know the key and you want to get the value, b开发者_如何学编程ut I want to do the opposite, going from value to key. Is it possible?
Yes, you have to iterate over the values in the map and then store each key in a list:
for (Map.Entry<K,V> entry : map.entrySet()) {
V value = entry.getValue();
if (value.equals(someTargetValue) {
// add key (entry.getKey()) to list
}
}
Or you could use a bidirectional map, though do note:
This map enforces the restriction that there is a 1:1 relation between keys and values, meaning that multiple keys cannot map to the same value.
Well, I am not an expert on Google Project LambdaJ, but it certainly offers a few cool alternatives.
Supposing you have a map with all the days of the month:
month.put(1,"Monday");
month.put(2,"Tuesday");
month.put(3,"Wednesday");
...
Then we could easily achieve what you want like this:
Set<Integer> result = with(month).retainValues(is("Friday")).keySet();
Or even a few more interesting searches like:
Set<Integer> result = with(month).retainValues(anyOf(is("Monday"),is("Friday"))).keySet();
Without iterating all the keys looking for the value you can use an Apache Commons BidiMap
A Map is a mathematical entry which doesn't imply that a reverse mapping is possible. That said you might be able to create a "reverse" mapping if every mapped value is unique. Naturally, you'll have to encapsulate all the data manipulations in methods that update both Maps appropriately.
Map<Key, Value> normal;
Map<Value, Key> reverse;
If every mapped value is not unique, then you need to create a reverse mapping of a value to a list of keys.
Map<Key, Value> normal;
Map<Value, List<Key>> reverse;
Finally, if you don't care about fast access, you can iterate over the entire Map looking for Values. Since you'll need both the Value and the Key, it is probably best to iterate over the Map.Entry items.
Value searchingFor = ...;
Map<Key, Value> normal;
List<Key> keys = new ArrayList<Key>();
for (Map.Entry<Key, Value> entry : normal.entrySet()) {
if (entry.getValue().equals(searchingFor)) {
keys.add(entry.getKey());
}
}
The technique you choose to use will depend heavily on whether it is better to trade speed for memory footprint. Generally having an extra Map is faster due to the hashing being done on the Value(s), but costs extra memory. Having a loop over the Map.Entry(s) is slower, but costs less memory.
Here they already talked about Bidirectional maps. Nowadays, Guava (https://github.com/google/guava) offers a nice BiMap that you can use for that purpose:
https://github.com/google/guava/wiki/NewCollectionTypesExplained#bimap
精彩评论