I'm implementing a NavigableMap-implementing LinkedHashMap in Java. (There don't seem to be many (any?) reasons why LinkedHashMap doesn't implement NavigableMap already, but I digress...)
I've written lowerKey(), lowerEntry(), higherKey(), and higherEntry() by iterating the entrySet(). I don't see any way in these cases to avoid iterating the entire entrySet().
For floorKey(), floorEntry(), ceilingKey(), and ceilingEntry(), in the case that the key exists, I'd like to avoid the expense of iterating the entrySet(), considering that I can already get the value with plain-old get().
Is there a way to get the Map.Entry for a particular key, rather than just the value? Thanks.
You have the key, and you can get the value associated with the key using get, now all you gotta do is to make a Map.Entry, and we can do that with the Map.entry factory method:
var value = theBackingLinkedHashMap.get(key);
if (value == null) {
return null;
}
return Map.entry(key, value);
The entry returned by entry does have two caveats that you should be aware of:
does not allow null keys, so your NavigableLinkedHashMap would need to not allow null keys either
is immutable, so you cannot call setValue.
But other than that, it will work as if you got the Map.Entry from inside the backing LinkedHashMap, and it does fulfil the contract of ceilingEntry, floorEntry etc, since they just ask for a "a key-value mapping", and doesn't require that it has to have the mutability as the map itself or anything like that. For example, this is ceilingEntry:
Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key.
I would use TreeSet to keep the keys in the NavigableMap class. See example below:
import java.util.*;
public class Main{
public static void main(String[] args) {
NavMap<Integer, String> map = new NavMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.put(4, "four");
map.put(10, "ten");
System.out.println(map.lowerKey(3)); //2
System.out.println(map.higherKey(3)); //4
System.out.println(map.higherEntry(3)); // 4:four
System.out.println(map.ceilingKey(7)); //10
System.out.println(map.floorKey(7)); //4
System.out.println(map.floorEntry(10)); // 4:four
}
}
class NavMap<K extends Comparable,V extends Comparable> extends LinkedHashMap<K,V>{
private TreeSet<K> keys = new TreeSet<>();
public Set<K> keySet(){ return keys; }
public K lowerKey (K k){ return keys.lower(k); }
public K higherKey (K k){ return keys.higher(k); }
public K floorKey (K k){ return keys.floor(k); }
public K ceilingKey(K k){ return keys.ceiling(k);}
public Map.Entry<K,V> lowerEntry(K k) { return newEntry(lowerKey(k), get(lowerKey(k)));}
public Map.Entry<K,V> higherEntry(K k) { return newEntry(higherKey(k), get(higherKey(k)));}
public Map.Entry<K,V> floorEntry(K k) { return newEntry(floorKey(k), get(floorKey(k)));}
public Map.Entry<K,V> ceilingEntry(K k) { return newEntry(ceilingKey(k),get(ceilingKey(k)));}
private Map.Entry<K,V> newEntry(K k, V v) { return new AbstractMap.SimpleEntry<>(k,v);}
public V put(K key, V value){
keys.add(key);
return super.put(key, value);
}
}
Output:
2
4
4=four
10
4
10=ten
#Sweeper's comment on his answer got me thinking. The solution I came up with was to maintain a Map from Key to Entry inside my class. That way I have a way of having O(1) access to the entrySet. Like so:
Map<K, Map.Entry<K, V>> entryMap = new HashMap<>();
for(final currentEntry : entrySet())
{
entryMap.put(currentEntry.getKey(), currentEntry);
}
I just need to update this Map every time an operation runs which changes the keySet. I only need to update the one entry in this Map that would be affected. That sounds like it wouldn't be very expensive.
You could do something like this.
Map<String,Integer> map = Map.of("Foo", 123, "Bar", 234);
Function<String, Entry<String,Integer>> getEntry =
getEntryFnc(map);
System.out.println(getEntry.apply("Foo"));
System.out.println(getEntry.apply("Bar"));
System.out.println(getEntry.apply("Baz"));
prints
Foo=123
Bar=234
Baz=null
Returns a lambda which builds an entry using the supplied key and map.
public static <K,V> Function<K, Entry<K,V>> getEntryFnc(Map<K,V> map) {
return key->
new AbstractMap.SimpleEntry<>(key, map.get(key));
};
}
Is there any easy way to get the keys for which same value exist?
Or more importantly, how can i get the number of same-value-more-than-once occurrences?
Consider the hashmap:
1->A
2->A
3->A
4->B
5->C
6->D
7->D
here same-value-more-than-once occurred 3 times(A two times, D one time).That(3) is what i want in return.
I could iterate over the hashmap by the keyset/map.values() list, but it seems quite cumbersome to do that way. Any suggestions or solutions?
EDIT :
My context is, i'm working on a timetable generator. The data-structure for a time-slot is
{String day-hour, HashMap<String,Event> Rooms}
For a day-hour, some Event-s are assigned on Rooms map. While checking the fitness of the solution, i need to know if one staff is assigned multiple events on same hour. Hence i want to check how many violations are there in Rooms map by the values Event.getStaff() .
EDIT :
Values are objects here, I don't want to count the occurrences of the same objects, rather a field of the object. The EVENT object has a field staff and i need to count the multiple occurrences of staffs.
I could iterate over the hashmap by the keyset/map.values() list, but it seems quite cumbersome to do that way.
Well it's inefficient, but there's not a lot you can do about that, without having some sort of multi-map to store reverse mappings of values to keys.
It doesn't have to be cumbersome in terms of code though, if you use Guava:
Multiset<String> counts = HashMultiSet.create(map.values());
for (Multiset.Entry<String> entry : counts.entrySet) {
if (entry.getCount() > 1) {
System.out.println(entry.getElement() + ": " + entry.getCount());
}
}
This is nice way I think:
int freq = Collections.frequency(map.values(), "A");
which returns "3" for your example. Cheers!
EDIT: sorry I misunderstood the question in my first attempt, this should do the trick:
int k = 0;
Set<String> set = new HashSet<String>(map.values());
for (String s : set) {
int i = Collections.frequency(map.values(), s);
k += i > 1 ? i - 1 : 0;
}
You will still not be able to retreive the actual keys though. But that was not the most important thing, right?
How about (expanding on Jon's answer)
Multiset<V> counts = HashMultiSet.create(map.values());
Predicate<Map.Entry<K,V>> pred = new Predicate<Map.Entry<K,V>>(){
public boolean apply(Map.Entry<K,V> entry){
return counts.count(entry.getValue()) > 1;
}
}
Map<K,V> result = Maps.filterEntries(map, pred);
This will result in a map where each key is mapped to a value that is duplicated.
This answer is only needed to address the first part of the question (the "less important part"), to get the keys that have duplicate values.
I don't know the context but what if you use a multimap:
Map<String, List<Integer>>
so this way your map would look like this:
A->1, 2, 3
B->4
C->5
D->6, 7
You could create a wrapper class around (Hash)Map, with decorating the put()-remove() methods to maintain another map, of which the values of the original Map are the keys, and the values are the numbers of occurrences. Then you just have to implement the method to query that...
However, this is rather tricky! You have to be careful not to have links to objects that are not in the map anymore... This could lead to a memory leak!
Also, null value tolerance has to be taken into count...
public static class MyCountingMap<K,V> implements Map<K,V> {
private final Map<K,V> internalMap;
//hashmap tolerates null as a key!
private final Map<V,Long> counterMap = new HashMap<V, Long>();
public MyCountingMap(Map<K, V> internalMap) {
super();
this.internalMap = internalMap;
}
#Override
public V put(K key, V value) {
boolean containedOriginally = internalMap.containsKey(key);
V origValue = internalMap.put(key, value);
updateCounterPut(containedOriginally, origValue, value);
return origValue;
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
//now this is the awkward part...
//this whole thing could be done through a loop and the put() method,
//but I'd prefer to use the original implementation...
for(Map.Entry<? extends K, ? extends V> entry :m.entrySet()) {
boolean containedOriginally = internalMap.containsKey(entry.getKey());
V origValue = internalMap.get(entry.getKey());
updateCounterPut(containedOriginally, origValue, entry.getValue());
}
internalMap.putAll(m);
}
// this method updates the counter
private void updateCounterPut(boolean containedOriginally, V origValue, V newValue) {
//if it was in the map, and it is different than the original, decrement
if(containedOriginally && isDifferent(origValue, newValue))
{
decrement(origValue);
}
//if it was NOT in the map, or the value differs
if(!containedOriginally || isDifferent(origValue, newValue)) {
increment(newValue);
}
}
// nothing special, just nicer to extract this to a method. Checks if the two values are the same or not.
private static boolean isDifferent(Object origValue, Object newValue) {
return ((origValue==null && newValue!=null) || !(origValue!=null && origValue.equals(newValue)));
}
//this method returns the counter value for the map value
public Long getValueCount(V value) {
return counterMap.get(value);
}
#Override
public V remove(Object key) {
V toReturn = internalMap.remove(key);
if(toReturn!=null) {
decrement(toReturn);
}
return toReturn;
}
private void increment(V value) {
Long count = counterMap.get(value);
if(count == null) {
count = 0L;
}
counterMap.put(value, count+1);
}
private void decrement(V value) {
Long count = counterMap.get(value);
if(count == null) {
count = 0L;
}
//last! Have to remove reference to prevent memory leak!!
if(count == 1L) {
counterMap.remove(value);
} else {
counterMap.put(value, count-1);
}
}
//... boring wrapper methods ...
public void clear() { internalMap.clear(); }
public boolean containsKey(Object key) { return internalMap.containsKey(key); }
public boolean containsValue(Object value) { return internalMap.containsValue(value); }
public Set<Entry<K, V>> entrySet() { return internalMap.entrySet(); }
public V get(Object key) { return internalMap.get(key); }
public boolean isEmpty() { return internalMap.isEmpty(); }
public Set<K> keySet() { return internalMap.keySet(); }
public int size() { return internalMap.size(); }
public Collection<V> values() { return internalMap.values(); }
}
I have a list of objects. The objects are given an ID and stored in a Hashtable. If I need an object with particular ID, I simply say:
ht.get(ID);
However, sometimes I need to get the ID for a given object:
ht.get(Object);
My first idea is to use two different HashTables; one for ID -> Object mapping and the other for Object -> ID mapping.
Does this sound like a good enough solution?
If you cannot use external collections (as you seem to not want to use given one of your comments) you could write a simple class to do what you want (which, yes, is essentially your first thought), along the lines of (I didn't compile this, and it is just a first thought so could be a bad idea, etc ...):
EDIT: now there are two versions, one that allows for duplicate values and one that does not. The ones that does not will remove the key if the value is overwritten.
This version does not allow duplicate values:
class Foo<K, V>
{
private final Map<K, V> keyValue;
private final Map<V, K> valueKey;
{
keyValue = new HashMap<K, V>();
valueKey = new HashMap<V, K>();
}
// this makes sure that if you do not have duplicate values.
public void put(final K key, final V value)
{
if(keyValue.containsValue(value))
{
keyValue.remove(valueKey.get(value));
}
keyValue.put(key, value);
valueKey.put(value, key);
}
public V getValueForKey(final K key)
{
return (keyValue.get(key));
}
public K getKeyForValue(final V value)
{
return (valueKey.get(value));
}
public static void main(final String[] argv)
{
Foo<String, String> foo;
foo = new Foo<String, String>();
foo.put("a", "Hello");
foo.put("b", "World");
foo.put("c", "Hello");
System.out.println(foo.getValueForKey("a"));
System.out.println(foo.getValueForKey("b"));
System.out.println(foo.getValueForKey("c"));
System.out.println(foo.getKeyForValue("Hello"));
System.out.println(foo.getKeyForValue("World"));
}
}
This version allows duplicated values and gives you back a list of all of the keys that have a given value:
class Foo<K, V>
{
private final Map<K, V> keyValue;
private final Map<V, List<K>> valueKeys;
{
keyValue = new HashMap<K, V>();
valueKeys = new HashMap<V, List<K>>();
}
public void put(final K key, final V value)
{
List<K> values;
keyValue.put(key, value);
values = valueKeys.get(value);
if(values == null)
{
values = new ArrayList<K>();
valueKeys.put(value, values);
}
values.add(key);
}
public V getValueForKey(final K key)
{
return (keyValue.get(key));
}
public List<K> getKeyForValue(final V value)
{
return (valueKeys.get(value));
}
public static void main(final String[] argv)
{
Foo<String, String> foo;
foo = new Foo<String, String>();
foo.put("a", "Hello");
foo.put("b", "World");
foo.put("c", "Hello");
System.out.println(foo.getValueForKey("a"));
System.out.println(foo.getValueForKey("b"));
System.out.println(foo.getValueForKey("c"));
System.out.println(foo.getKeyForValue("Hello"));
System.out.println(foo.getKeyForValue("World"));
}
}
Hiding the two maps in a class is a good idea, because of you find a better way later all you need to do is replace the innards of the class and the rest of your code is left untouched.
If using an external library is OK, you should check BiMap on google collections:
http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/BiMap.html
What you are looking for is a bidirectional map. You can find it in the commons collections in the classes implementing the BidiMap interface or the Google Guava.
What you are looking for is a Bi-directional Map.
Try Apache Collections BidiMap.
http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/BidiMap.html
Not that I know of immediatley but you can build one ... How about having a single collection of your objects and several lookup structures (hashmaps or trees) that don't store the objects themselves (for memory saving reasons) but the index into your single collection? This way you use the appropriate lookup structure you need (Id -> object or vice versa) get back an integer value that you can index into your original collection. This way you can do more than a bidirectional lookup in case you need to do so in the future.
If I have the value "foo", and a HashMap<String> ftw for which ftw.containsValue("foo") returns true, how can I get the corresponding key? Do I have to loop through the hashmap? What is the best way to do that?
If your data structure has many-to-one mapping between keys and values you should iterate over entries and pick all suitable keys:
public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
Set<T> keys = new HashSet<T>();
for (Entry<T, E> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
keys.add(entry.getKey());
}
}
return keys;
}
In case of one-to-one relationship, you can return the first matched key:
public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
for (Entry<T, E> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
return entry.getKey();
}
}
return null;
}
In Java 8:
public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
return map.entrySet()
.stream()
.filter(entry -> Objects.equals(entry.getValue(), value))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
Also, for Guava users, BiMap may be useful. For example:
BiMap<Token, Character> tokenToChar =
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
If you choose to use the Commons Collections library instead of the standard Java Collections framework, you can achieve this with ease.
The BidiMap interface in the Collections library is a bi-directional map, allowing you to map a key to a value (like normal maps), and also to map a value to a key, thus allowing you to perform lookups in both directions. Obtaining a key for a value is supported by the getKey() method.
There is a caveat though, bidi maps cannot have multiple values mapped to keys, and hence unless your data set has 1:1 mappings between keys and values, you cannot use bidi maps.
If you want to rely on the Java Collections API, you will have to ensure the 1:1 relationship between keys and values at the time of inserting the value into the map. This is easier said than done.
Once you can ensure that, use the entrySet() method to obtain the set of entries (mappings) in the Map. Once you have obtained the set whose type is Map.Entry, iterate through the entries, comparing the stored value against the expected, and obtain the corresponding key.
Support for bidi maps with generics can be found in Google Guava and the refactored Commons-Collections libraries (the latter is not an Apache project). Thanks to Esko for pointing out the missing generic support in Apache Commons Collections. Using collections with generics makes more maintainable code.
Since version 4.0 the official Apache Commons Collections™ library supports generics.
See the summary page of the "org.apache.commons.collections4.bidimap" package for the list of available implementations of the BidiMap, OrderedBidiMap and SortedBidiMap interfaces that now support Java generics.
public class NewClass1 {
public static void main(String[] args) {
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Entry<Integer, String> entry : testMap.entrySet()) {
if (entry.getValue().equals("c")) {
System.out.println(entry.getKey());
}
}
}
}
Some additional info... May be useful to you
Above method may not be good if your hashmap is really big. If your hashmap contain unique key to unique value mapping, you can maintain one more hashmap that contain mapping from Value to Key.
That is you have to maintain two hashmaps
1. Key to value
2. Value to key
In that case you can use second hashmap to get key.
You could insert both the key,value pair and its inverse into your map structure
map.put("theKey", "theValue");
map.put("theValue", "theKey");
Using map.get("theValue") will then return "theKey".
It's a quick and dirty way that I've made constant maps, which will only work for a select few datasets:
Contains only 1 to 1 pairs
Set of values is disjoint from the set of keys (1->2, 2->3 breaks it)
I think your choices are
Use a map implementation built for this, like the BiMap from google collections. Note that the google collections BiMap requires uniqueless of values, as well as keys, but it provides high performance in both directions performance
Manually maintain two maps - one for key -> value, and another map for value -> key
Iterate through the entrySet() and to find the keys which match the value. This is the slowest method, since it requires iterating through the entire collection, while the other two methods don't require that.
Using Java 8:
ftw.forEach((key, value) -> {
if (value.equals("foo")) {
System.out.print(key);
}
});
Decorate map with your own implementation
class MyMap<K,V> extends HashMap<K, V>{
Map<V,K> reverseMap = new HashMap<V,K>();
#Override
public V put(K key, V value) {
// TODO Auto-generated method stub
reverseMap.put(value, key);
return super.put(key, value);
}
public K getKey(V value){
return reverseMap.get(value);
}
}
There is no unambiguous answer, because multiple keys can map to the same value. If you are enforcing unique-ness with your own code, the best solution is to create a class that uses two Hashmaps to track the mappings in both directions.
If you build the map in your own code, try putting the key and value in the map together:
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
Then when you have a value, you also have the key.
I think this is best solution, original address: Java2s
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] argv) {
Map<String, String> map = new HashMap<String, String>();
map.put("1","one");
map.put("2","two");
map.put("3","three");
map.put("4","four");
System.out.println(getKeyFromValue(map,"three"));
}
// hm is the map you are trying to get value from it
public static Object getKeyFromValue(Map hm, Object value) {
for (Object o : hm.keySet()) {
if (hm.get(o).equals(value)) {
return o;
}
}
return null;
}
}
An easy usage:
if you put all data in hasMap and you have item = "Automobile", so you are looking its key in hashMap. that is good solution.
getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
To find all the keys that map to that value, iterate through all the pairs in the hashmap, using map.entrySet().
I'm afraid you'll just have to iterate your map. Shortest I could come up with:
Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,String> entry = iter.next();
if (entry.getValue().equals(value_you_look_for)) {
String key_you_look_for = entry.getKey();
}
}
for(int key: hm.keySet()) {
if(hm.get(key).equals(value)) {
System.out.println(key);
}
}
It sounds like the best way is for you to iterate over entries using map.entrySet() since map.containsValue() probably does this anyway.
For Android development targeting API < 19, Vitalii Fedorenko one-to-one relationship solution doesn't work because Objects.equals isn't implemented. Here's a simple alternative:
public <K, V> K getKeyByValue(Map<K, V> map, V value) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (value.equals(entry.getValue())) {
return entry.getKey();
}
}
return null;
}
You can use the below:
public class HashmapKeyExist {
public static void main(String[] args) {
HashMap<String, String> hmap = new HashMap<String, String>();
hmap.put("1", "Bala");
hmap.put("2", "Test");
Boolean cantain = hmap.containsValue("Bala");
if(hmap.containsKey("2") && hmap.containsValue("Test"))
{
System.out.println("Yes");
}
if(cantain == true)
{
System.out.println("Yes");
}
Set setkeys = hmap.keySet();
Iterator it = setkeys.iterator();
while(it.hasNext())
{
String key = (String) it.next();
if (hmap.get(key).equals("Bala"))
{
System.out.println(key);
}
}
}
}
I think keySet() may be well to find the keys mapping to the value, and have a better coding style than entrySet().
Ex:
Suppose you have a HashMap map, ArrayList res, a value you want to find all the key mapping to , then store keys to the res.
You can write code below:
for (int key : map.keySet()) {
if (map.get(key) == value) {
res.add(key);
}
}
rather than use entrySet() below:
for (Map.Entry s : map.entrySet()) {
if ((int)s.getValue() == value) {
res.add((int)s.getKey());
}
}
Hope it helps :)
Yes, you have to loop through the hashmap, unless you implement something along the lines of what these various answers suggest. Rather than fiddling with the entrySet, I'd just get the keySet(), iterate over that set, and keep the (first) key that gets you your matching value. If you need all the keys that match that value, obviously you have to do the whole thing.
As Jonas suggests, this might already be what the containsValue method is doing, so you might just skip that test all-together, and just do the iteration every time (or maybe the compiler will already eliminate the redundancy, who knows).
Also, relative to the other answers, if your reverse map looks like
Map<Value, Set<Key>>
you can deal with non-unique key->value mappings, if you need that capability (untangling them aside). That would incorporate fine into any of the solutions people suggest here using two maps.
You can get the key using values using following code..
ArrayList valuesList = new ArrayList();
Set keySet = initalMap.keySet();
ArrayList keyList = new ArrayList(keySet);
for(int i = 0 ; i < keyList.size() ; i++ ) {
valuesList.add(initalMap.get(keyList.get(i)));
}
Collections.sort(valuesList);
Map finalMap = new TreeMap();
for(int i = 0 ; i < valuesList.size() ; i++ ) {
String value = (String) valuesList.get(i);
for( int j = 0 ; j < keyList.size() ; j++ ) {
if(initalMap.get(keyList.get(j)).equals(value)) {
finalMap.put(keyList.get(j),value);
}
}
}
System.out.println("fianl map ----------------------> " + finalMap);
public static class SmartHashMap <T1 extends Object, T2 extends Object> {
public HashMap<T1, T2> keyValue;
public HashMap<T2, T1> valueKey;
public SmartHashMap(){
this.keyValue = new HashMap<T1, T2>();
this.valueKey = new HashMap<T2, T1>();
}
public void add(T1 key, T2 value){
this.keyValue.put(key, value);
this.valueKey.put(value, key);
}
public T2 getValue(T1 key){
return this.keyValue.get(key);
}
public T1 getKey(T2 value){
return this.valueKey.get(value);
}
}
In java8
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
Use a thin wrapper: HMap
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class HMap<K, V> {
private final Map<K, Map<K, V>> map;
public HMap() {
map = new HashMap<K, Map<K, V>>();
}
public HMap(final int initialCapacity) {
map = new HashMap<K, Map<K, V>>(initialCapacity);
}
public boolean containsKey(final Object key) {
return map.containsKey(key);
}
public V get(final Object key) {
final Map<K, V> entry = map.get(key);
if (entry != null)
return entry.values().iterator().next();
return null;
}
public K getKey(final Object key) {
final Map<K, V> entry = map.get(key);
if (entry != null)
return entry.keySet().iterator().next();
return null;
}
public V put(final K key, final V value) {
final Map<K, V> entry = map
.put(key, Collections.singletonMap(key, value));
if (entry != null)
return entry.values().iterator().next();
return null;
}
}
public static String getKey(Map<String, Integer> mapref, String value) {
String key = "";
for (Map.Entry<String, Integer> map : mapref.entrySet()) {
if (map.getValue().toString().equals(value)) {
key = map.getKey();
}
}
return key;
}
Simplest utility method to fetch a key of a given value from a Map:
public static void fetchValue(Map<String, Integer> map, Integer i)
{
Stream stream = map.entrySet().stream().filter(val-> val.getValue().equals(i)).map(Map.Entry::getKey);
stream.forEach(System.out::println);
}
detailed explaination:
Method fetchValue accepts the map, which has String as key and Integer as value.
Then we use entryset().stream() to convert result into a stream.
Next we use filter (intermediate operation) which gives us a value that is equal to the second argument.
Finally, we use forEach(final operation) to print our end result.
Found too many answers. Some were really great. But I was particularly looking for a way, so that I can get the value using loops.
So here is finally what I did:
For a HashMap 1-to-1 relation:
Map<String, String> map = new HashMap<String, String>();
map.put("abc", "123");
map.put("xyz", "456");
for(Entry<String, String> entry : map.entrySet()) {
if(entry.getValue().equalsIgnoreCase("456")) {
System.out.println(entry.getKey());
}
}
Output: "xyz"
For a HashMap 1-to-many relation:
Map<String, ArrayList<String>> service = new HashMap<String, ArrayList<String>>();
service.put("abc", new ArrayList<String>());
service.get("abc").add("a");
service.get("abc").add("b");
service.get("abc").add("c");
service.put("xyz", new ArrayList<String>());
service.get("xyz").add("x");
service.get("xyz").add("y");
service.get("xyz").add("z");
for(Entry<String, ArrayList<String>> entry : service.entrySet()) {
ArrayList<String> values = entry.getValue();
for(String value : values) {
if(value.equalsIgnoreCase("x")) {
System.out.println(entry.getKey());
}
}
}
Output: xyz
-Thanks
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class ValueKeysMap<K, V> extends HashMap <K,V>{
HashMap<V, Set<K>> ValueKeysMap = new HashMap<V, Set<K>>();
#Override
public boolean containsValue(Object value) {
return ValueKeysMap.containsKey(value);
}
#Override
public V put(K key, V value) {
if (containsValue(value)) {
Set<K> keys = ValueKeysMap.get(value);
keys.add(key);
} else {
Set<K> keys = new HashSet<K>();
keys.add(key);
ValueKeysMap.put(value, keys);
}
return super.put(key, value);
}
#Override
public V remove(Object key) {
V value = super.remove(key);
Set<K> keys = ValueKeysMap.get(value);
keys.remove(key);
if(keys.size() == 0) {
ValueKeysMap.remove(value);
}
return value;
}
public Set<K> getKeys4ThisValue(V value){
Set<K> keys = ValueKeysMap.get(value);
return keys;
}
public boolean valueContainsThisKey(K key, V value){
if (containsValue(value)) {
Set<K> keys = ValueKeysMap.get(value);
return keys.contains(key);
}
return false;
}
/*
* Take care of argument constructor and other api's like putAll
*/
}
/**
* This method gets the Key for the given Value
* #param paramName
* #return
*/
private String getKeyForValueFromMap(String paramName) {
String keyForValue = null;
if(paramName!=null)) {
Set<Entry<String,String>> entrySet = myMap().entrySet();
if(entrySet!=null && entrySet.size>0) {
for(Entry<String,String> entry : entrySet) {
if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) {
keyForValue = entry.getKey();
}
}
}
}
return keyForValue;
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class M{
public static void main(String[] args) {
HashMap<String, List<String>> resultHashMap = new HashMap<String, List<String>>();
Set<String> newKeyList = resultHashMap.keySet();
for (Iterator<String> iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) {
String hashKey = (String) iterator.next();
if (!newKeyList.contains(originalHashMap.get(hashKey))) {
List<String> loArrayList = new ArrayList<String>();
loArrayList.add(hashKey);
resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
} else {
List<String> loArrayList = resultHashMap.get(originalHashMap
.get(hashKey));
loArrayList.add(hashKey);
resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
}
}
System.out.println("Original HashMap : " + originalHashMap);
System.out.println("Result HashMap : " + resultHashMap);
}
}
My 2 cents.
You can get the keys in an array and then loop through the array. This will affect performance of this code block if the map is pretty big , where in you are getting the keys in an array first which might consume some time and then you are looping. Otherwise for smaller maps it should be ok.
String[] keys = yourMap.keySet().toArray(new String[0]);
for(int i = 0 ; i < keys.length ; i++){
//This is your key
String key = keys[i];
//This is your value
yourMap.get(key)
}
While this does not directly answer the question, it is related.
This way you don't need to keep creating/iterating. Just create a reverse map once and get what you need.
/**
* Both key and value types must define equals() and hashCode() for this to work.
* This takes into account that all keys are unique but all values may not be.
*
* #param map
* #param <K>
* #param <V>
* #return
*/
public static <K, V> Map<V, List<K>> reverseMap(Map<K,V> map) {
if(map == null) return null;
Map<V, List<K>> reverseMap = new ArrayMap<>();
for(Map.Entry<K,V> entry : map.entrySet()) {
appendValueToMapList(reverseMap, entry.getValue(), entry.getKey());
}
return reverseMap;
}
/**
* Takes into account that the list may already have values.
*
* #param map
* #param key
* #param value
* #param <K>
* #param <V>
* #return
*/
public static <K, V> Map<K, List<V>> appendValueToMapList(Map<K, List<V>> map, K key, V value) {
if(map == null || key == null || value == null) return map;
List<V> list = map.get(key);
if(list == null) {
List<V> newList = new ArrayList<>();
newList.add(value);
map.put(key, newList);
}
else {
list.add(value);
}
return map;
}