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;
}
Related
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));
};
}
I am seaching for a data structure that is almost exactly a HashMap<String,Integer>, but the problem with HashMaps is that most of the data stored in key value pairs is lost by calling the putAll() method on two HashMaps, due to the replacement behavior of putVal() in line 655 of the java/util/HashMap.java.
This is basically the change that I want:
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
-- e.value = value;
++ e.value = value + oldValue;
afterNodeAccess(e);
return oldValue;
}
Is there an existing data structure, that I've overlooked that would do such a thing, or how do I create a class that is basically a HashMap with that one change?
I've already tried to code something, but doen't work how I want it to... In fact it doen't matter if I set the put method on #Override, do it like that, or delete it completely - the replacing behavior ofcourse stays the same, because putAll() uses putVal() that I can't reach / change from the outside - or I at least don't know how...
/**
* doesn't work, putAll() uses putVal() that I can't reach
*/
public class SumHashMap<K> extends HashMap<K, Integer> {
private static final long serialVersionUID = 1L;
public Integer put(K key, Integer value) {
Integer oldValue = get(key);
if (oldValue == null)
return super.put(key, value);
return super.put(key, oldValue + value);
}
}
Thanks in advance
Additional info:
I want to use the putAll() function in the reduction of a stream out of custom HashMaps.
If I have two custom HashMaps of this sort {"key1" : 2, "key3" : 4} and {"key3" : 1} the result of a.putAll(b) should be {"key1" : 2, "key3" : 5}
You don't need a new data structure for this, you don't even need a new class that inherits from HashMap. Instead, use the Map.merge method:
newMap.forEach((k, v) -> oldMap.merge(k, v, Integer::sum));
This code uses Map.forEach to traverse the entries of the new map (the one you'd receive as an argument in putAll) and uses Map.merge (along with Integer::sum) to merge its entries into an already existing map (which I've named oldMap here).
I think this is what you are looking for. I made it so that the key can be any type. If you want, you can remove the generic for the key and just extend HashMap<String, Integer>.
import java.util.HashMap;
import java.util.Map;
public class AddingHashMap<K> extends HashMap<K, Integer> {
#Override
public Integer put(K key, Integer value) {
Integer existingValue = super.get(key);
if (existingValue == null) {
existingValue = value;
} else {
existingValue = existingValue.intValue() + value.intValue();
}
return super.put(key, existingValue);
}
#Override
public void putAll(Map<? extends K, ? extends Integer> m) {
m.entrySet().forEach(entry -> {
this.put(entry.getKey(), entry.getValue());
});
}
}
Here is it working:
public static void main(String[] argv) {
AddingHashMap<String> myAddingHashMap = new AddingHashMap<>();
myAddingHashMap.put("One", 1);
myAddingHashMap.put("Two", 2);
myAddingHashMap.put("One", 3);
myAddingHashMap.entrySet().forEach(entry -> System.out.println(entry.getKey() + " - " + entry.getValue()));
}
Outputs:
One - 4
Two - 2
Later edit: Keep in mind that this is NOT thread-safe.
I don't think there is a datastructure that does that. The purpose of the datastructure is to store data, not to have logic associated to it. The HashMap can store key-value pairs for you but if you need some more advanced, or specific, logic associated with certain operations, you'll need to add it yourself.
One way is to wrap the map in a class which has this logic. Another might be to implenent the Map interface yourself (which could also use a HashMap internally) though I would not recommend that since changing the behaviour is not a great idea.
A minimal wrapper providing adding functionality:
public class AddingMap {
private final HashMap<String, Integer> map;
public AddingMap() {
map = new HashMap<>();
}
public void add(String key, Integer value) {
map.put(key, map.getOrDefault(key, 0) + value);
}
public Integer get(String key) {
return map.get(key);
}
}
Edit
Shouldn't have finished writing the answer half way...
Indeed, the addAll() method is missing:
public void addAll(Map<String, Integer> map) {
map.entrySet().forEach(e -> this.add(e.getKey(), e.getValue()));
}
I want to retrieve the specific key associated with the value in a hashmap
I want to retrieve the key of "ME", how can I get it?
Code snippet :
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"I");
map.put(2,"ME");
There's a small problem with what you are trying to do. There can be multiple occurrences of the same value in a hashmap, so if you look up the key by value, there might be multiple results (multiple keys with the same value).
Nevertheless, if you are sure this won't occur, it can be done; see the following example:
import java.util.*;
public class Main {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(5, "vijf");
map.put(36, "zesendertig");
}
static Integer getKey(HashMap<Integer, String> map, String value) {
Integer key = null;
for(Map.Entry<Integer, String> entry : map.entrySet()) {
if((value == null && entry.getValue() == null) || (value != null && value.equals(entry.getValue()))) {
key = entry.getKey();
break;
}
}
return key;
}
}
Iterate over the entries of the map :
for(Entry<Integer, String> entry : map.entrySet()){
if("ME".equals(entry.getValue())){
Integer key = entry.getKey();
// do something with the key
}
}
You will have to iterate through the collection of keys to find your value.
Take a look at this post for details: Java Hashmap: How to get key from value?
If your values are guaranteed to be unique use Guava BiMap (the HashMap counterpart is called HashBiMap.
Integer key = map.inverse().get("ME");
Guava Documentation.
/**
* Return keys associated with the specified value
*/
public List<Integer> getKey(String value, Map<Integer, String> map) {
List<Integer> keys = new ArrayList<Integer>();
for(Entry<Integer, String> entry:map.entrySet()) {
if(value.equals(entry.getValue())) {
keys.add(entry.getKey());
}
}
return keys;
}
I would like to know: how can I iterate through a 2D map? I have a centralMap:
private final Map<String, Map<String, String>> centralMap =
new HashMap<String, Map<String, String>>();
which contains another map:
Map<String,String> nestedMap = new HashMap<String, String>();
as Value, and the second one is created in the "put" method, so that in the constructor, i have just the centralMap. Now i want to redefine this method and to get complete entry of the map (the 2 keys and the value for each element)
public Iterator<Entry> iterator()
How should I proceed? If possible, how can I remove an element through the iterator without having a problem?
Iterators are meant to operate on a collection, such as the keyset of your first map, or the values (which are a collection of maps) of your nested one. You cannot expect the iterator renove method to understand your complex structure.
I would suggest that you build your own class for this, with your own convenience methods that do what you described.
Also, going on a limb here: make sure you didn't just want to have a multimap. If so, have a look, for example, at guava's HashMultimap
You apply the same procedure as if you were iterating over a single map, you just do it twice:
public void printNestedMap(Map<String, Map<String, String>> map)
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
System.out.println("Key1: " + pairs.getKey());
//print the inner Map
printMap((Map<String, String>)pairs.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
EDIT
It would actually be better to move the iteration over a single map to a different method to be called in this scenario.
public void printMap(Map<String, String>> map)
{
Iterator it = map.entrySet().iterator();
while(it.hasNext())
{
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
it.remove();
}
}
EDIT 2: Test Program
import java.util.*;
public class TestMap
{
public static void main(String[] args)
{
Map<String, String> innerMap = new HashMap<>();
Map<String, Map<String, String>> outerMap = new HashMap<>();
innerMap.put("Key1", "Val1");
innerMap.put("Key2", "Val2");
innerMap.put("Key3", "Val3");
innerMap.put("Key4", "Val4");
outerMap.put("OuterKey1", innerMap);
printNestedMap(outerMap);
}
public static void printNestedMap(Map<String, Map<String, String>> map)
{
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
System.out.println("Key1: " + pairs.getKey());
//print the inner Map
printMap((Map<String, String>)pairs.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
public static void printMap(Map<String, String> map)
{
Iterator it = map.entrySet().iterator();
while(it.hasNext())
{
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
it.remove();
}
}
}
Output:
Key1: OuterKey1
Key2: Key2 Value2: Val2
Key2: Key1 Value2: Val1
Key2: Key4 Value2: Val4
Key2: Key3 Value2: Val3
If you want to get Map.Entry elements containing the two keys and the value, it will really be much more natural to create a class Pair<String, String> that combines the two keys in a single element and use that as the key in a single map rather than nesting maps.
If you do this, your main structure will be a Map<Pair<String, String>, String> and using the Map.entrySet() method will give you a Set<Map.Entry<String, String>, String> from which you can get an iterator that gives approximately what you're after.
If you need to have a Map<String, Map<String, String>> for other reasons, it is also possible to convert this into the structure described above by reasonably simple code, and this might be the most sensible way of getting the information out of it.
Edit Note:
The Pair class described above is essentially the same as Map.Entry, so you could avoid creating a new class for the key by building a Map<Map.Entry<String, String>, String>. I think it makes the code a bit less clear, but it can certainly be made functionally equivalent.
Sample Code
In the code below, I have defined the Pair class as an inner static (for real use, you might want to extract as an independent class), and written a conversion that takes a nested map as you describe, converts it to the form I've suggested, and uses an iterator on the entries of the converted map to print the values.
The iterator could of course be used for other things, and the convert method and Pair class are generic.
import java.util.*;
public class TestMap
{
public static void main(String[] args)
{
Map<String, String> innerMap1 = new HashMap<String, String>();
Map<String, String> innerMap2 = new HashMap<String, String>();
Map<String, Map<String, String>> outerMap = new HashMap<String, Map<String, String>>();
innerMap1.put("InnerKey1", "Val1");
innerMap1.put("InnerKey2", "Val2");
innerMap1.put("InnerKey3", "Val3");
innerMap1.put("InnerKey4", "Val4");
innerMap2.put("InnerKey5", "Val5");
innerMap2.put("InnerKey6", "Val6");
innerMap2.put("InnerKey7", "Val7");
innerMap2.put("InnerKey8", "Val8");
outerMap.put("OuterKey1", innerMap1);
outerMap.put("OuterKey2", innerMap2);
Map<Pair<String, String>, String> convertedMap = convert(outerMap);
for (Map.Entry<Pair<String, String>, String> entry: convertedMap.entrySet()) {
System.out.println(String.format("OuterKey: %s, InnerKey: %s, Value: %s",
entry.getKey().getFirst(),
entry.getKey().getSecond(),
entry.getValue()
));
}
}
private static <K1,K2,V> Map<Pair<K1, K2>,V> convert(Map<K1, Map<K2,V>> nestedMap) {
Map<Pair<K1, K2>, V> result = new HashMap<Pair<K1, K2>, V>();
for (Map.Entry<K1, Map<K2, V>> outerEntry: nestedMap.entrySet()) {
final K1 outerKey = outerEntry.getKey();
for (Map.Entry<K2, V> innerEntry: outerEntry.getValue().entrySet()) {
final K2 innerKey = innerEntry.getKey();
final V value = innerEntry.getValue();
result.put(new Pair<K1, K2>(outerKey, innerKey), value);
}
}
return result;
}
public static class Pair<T1, T2> {
private T1 first;
private T2 second;
public Pair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public T1 getFirst() {
return first;
}
public T2 getSecond() {
return second;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair pair = (Pair) o;
if (first != null ? !first.equals(pair.first) : pair.first != null) return false;
if (second != null ? !second.equals(pair.second) : pair.second != null) return false;
return true;
}
#Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
return result;
}
}
}
Note on Usage in context:
In your current code, you have a class with a field centralMap which is the map in your old nested form, and an integer counter for the size of the map.
This containing class has a method for adding entries that looks like this:
#Override
public String put(final String row, final String column, final String value) {
/**
* Second map which is contained by centralMap, that contain Strings as Keys
* and Values.
*/
Map<String, String> nestedMap;
if (centralMap.containsKey(row))
nestedMap = centralMap.get(row);
else
nestedMap = new HashMap<String, String>();
if (!nestedMap.containsKey(column))
counter++;
centralMap.put(row, nestedMap);
return nestedMap.put(column, value);
}
If instead of using the nested map at all, you change this field to a map of the suggested form, this method would become a bit simpler:
#Override
public String put(final String row, final String column, final String value) {
Pair<String, String> key = new Pair(row, column);
if (centralMap.contains(key)
counter++;
centralMap.put(key, value);
}
And you actually wouldn't need the counter anymore, as it will always contain the same value as centralMap.size().
Update:
From edits put in yesterday but now deleted, it's now clear to me (from edit history) that you want to build a single iterator that delegates to all the iterators of the map in correct sequence, and returns a simple structure containing both keys and the value.
This is certainly possible, and if I have time later, I might add some sample code for it. As was noted in another response, the iterator.remove() method may be impossible or unnatural.
Meanwhile, your requirements (as noted a comment on the same other response) is rather similar to what is supplied by guava's Table. That's open source, and looking at it may give you ideas. You can download the source for guava here.
Specifically, in guava's StandardTable, there is an inner class CellIterator, which looks like:
private class CellIterator implements Iterator<Cell<R, C, V>> {
final Iterator<Entry<R, Map<C, V>>> rowIterator
= backingMap.entrySet().iterator();
Entry<R, Map<C, V>> rowEntry;
Iterator<Entry<C, V>> columnIterator
= Iterators.emptyModifiableIterator();
#Override public boolean hasNext() {
return rowIterator.hasNext() || columnIterator.hasNext();
}
#Override public Cell<R, C, V> next() {
if (!columnIterator.hasNext()) {
rowEntry = rowIterator.next();
columnIterator = rowEntry.getValue().entrySet().iterator();
}
Entry<C, V> columnEntry = columnIterator.next();
return Tables.immutableCell(
rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
}
#Override public void remove() {
columnIterator.remove();
if (rowEntry.getValue().isEmpty()) {
rowIterator.remove();
}
}
}
You can't just copy this code as it depends on other things in guava, but it shows the basic pattern of what you have to do.
Recently I have conversation with a colleague about what would be the optimal way to convert List to Map in Java and if there any specific benefits of doing so.
I want to know optimal conversion approach and would really appreciate if any one can guide me.
Is this good approach:
List<Object[]> results;
Map<Integer, String> resultsMap = new HashMap<Integer, String>();
for (Object[] o : results) {
resultsMap.put((Integer) o[0], (String) o[1]);
}
With java-8, you'll be able to do this in one line using streams, and the Collectors class.
Map<String, Item> map =
list.stream().collect(Collectors.toMap(Item::getKey, item -> item));
Short demo:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test{
public static void main (String [] args){
List<Item> list = IntStream.rangeClosed(1, 4)
.mapToObj(Item::new)
.collect(Collectors.toList()); //[Item [i=1], Item [i=2], Item [i=3], Item [i=4]]
Map<String, Item> map =
list.stream().collect(Collectors.toMap(Item::getKey, item -> item));
map.forEach((k, v) -> System.out.println(k + " => " + v));
}
}
class Item {
private final int i;
public Item(int i){
this.i = i;
}
public String getKey(){
return "Key-"+i;
}
#Override
public String toString() {
return "Item [i=" + i + "]";
}
}
Output:
Key-1 => Item [i=1]
Key-2 => Item [i=2]
Key-3 => Item [i=3]
Key-4 => Item [i=4]
As noted in comments, you can use Function.identity() instead of item -> item, although I find i -> i rather explicit.
And to be complete note that you can use a binary operator if your function is not bijective. For example let's consider this List and the mapping function that for an int value, compute the result of it modulo 3:
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
Map<String, Integer> map =
intList.stream().collect(toMap(i -> String.valueOf(i % 3), i -> i));
When running this code, you'll get an error saying java.lang.IllegalStateException: Duplicate key 1. This is because 1 % 3 is the same as 4 % 3 and hence have the same key value given the key mapping function. In this case you can provide a merge operator.
Here's one that sum the values; (i1, i2) -> i1 + i2; that can be replaced with the method reference Integer::sum.
Map<String, Integer> map =
intList.stream().collect(toMap(i -> String.valueOf(i % 3),
i -> i,
Integer::sum));
which now outputs:
0 => 9 (i.e 3 + 6)
1 => 5 (i.e 1 + 4)
2 => 7 (i.e 2 + 5)
List<Item> list;
Map<Key,Item> map = new HashMap<Key,Item>();
for (Item i : list) map.put(i.getKey(),i);
Assuming of course that each Item has a getKey() method that returns a key of the proper type.
Just in case this question isn't closed as a duplicate, the right answer is to use Google Collections:
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
public String apply(Role from) {
return from.getName(); // or something else
}});
Short and sweet.
Using Java 8 you can do following :
Map<Key, Value> result= results
.stream()
.collect(Collectors.toMap(Value::getName,Function.identity()));
Value can be any object you use.
Alexis has already posted an answer in Java 8 using method toMap(keyMapper, valueMapper). As per doc for this method implementation:
There are no guarantees on the type, mutability, serializability, or
thread-safety of the Map returned.
So in case we are interested in a specific implementation of Map interface e.g. HashMap then we can use the overloaded form as:
Map<String, Item> map2 =
itemList.stream().collect(Collectors.toMap(Item::getKey, //key for map
Function.identity(), // value for map
(o,n) -> o, // merge function in case of conflict with keys
HashMap::new)); // map factory - we want HashMap and not any Map implementation
Though using either Function.identity() or i->i is fine but it seems Function.identity() instead of i -> i might save some memory as per this related answer.
Since Java 8, the answer by #ZouZou using the Collectors.toMap collector is certainly the idiomatic way to solve this problem.
And as this is such a common task, we can make it into a static utility.
That way the solution truly becomes a one-liner.
/**
* Returns a map where each entry is an item of {#code list} mapped by the
* key produced by applying {#code mapper} to the item.
*
* #param list the list to map
* #param mapper the function to produce the key from a list item
* #return the resulting map
* #throws IllegalStateException on duplicate key
*/
public static <K, T> Map<K, T> toMapBy(List<T> list,
Function<? super T, ? extends K> mapper) {
return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
}
And here's how you would use it on a List<Student>:
Map<Long, Student> studentsById = toMapBy(students, Student::getId);
A List and Map are conceptually different. A List is an ordered collection of items. The items can contain duplicates, and an item might not have any concept of a unique identifier (key). A Map has values mapped to keys. Each key can only point to one value.
Therefore, depending on your List's items, it may or may not be possible to convert it to a Map. Does your List's items have no duplicates? Does each item have a unique key? If so then it's possible to put them in a Map.
There is also a simple way of doing this using Maps.uniqueIndex(...) from Google guava libraries
Universal method
public static <K, V> Map<K, V> listAsMap(Collection<V> sourceList, ListToMapConverter<K, V> converter) {
Map<K, V> newMap = new HashMap<K, V>();
for (V item : sourceList) {
newMap.put( converter.getKey(item), item );
}
return newMap;
}
public static interface ListToMapConverter<K, V> {
public K getKey(V item);
}
Using java-8 streams
Map<Integer, String> map = results.stream().collect(Collectors.toMap(e -> ((Integer) e[0]), e -> (String) e[1]));
Without java-8, you'll be able to do this in one line Commons collections, and the Closure class
List<Item> list;
#SuppressWarnings("unchecked")
Map<Key, Item> map = new HashMap<Key, Item>>(){{
CollectionUtils.forAllDo(list, new Closure() {
#Override
public void execute(Object input) {
Item item = (Item) input;
put(i.getKey(), item);
}
});
}};
like already said, in java-8 we have the concise solution by Collectors:
list.stream().collect(
groupingBy(Item::getKey)
)
and also, you can nest multiple group passing an other groupingBy method as second parameter:
list.stream().collect(
groupingBy(Item::getKey, groupingBy(Item::getOtherKey))
)
In this way, we'll have multi level map, like this: Map<key, Map<key, List<Item>>>
Many solutions come to mind, depending on what you want to achive:
Every List item is key and value
for( Object o : list ) {
map.put(o,o);
}
List elements have something to look them up, maybe a name:
for( MyObject o : list ) {
map.put(o.name,o);
}
List elements have something to look them up, and there is no guarantee that they are unique: Use Googles MultiMaps
for( MyObject o : list ) {
multimap.put(o.name,o);
}
Giving all the elements the position as a key:
for( int i=0; i<list.size; i++ ) {
map.put(i,list.get(i));
}
...
It really depends on what you want to achive.
As you can see from the examples, a Map is a mapping from a key to a value, while a list is just a series of elements having a position each. So they are simply not automatically convertible.
Here's a little method I wrote for exactly this purpose. It uses Validate from Apache Commons.
Feel free to use it.
/**
* Converts a <code>List</code> to a map. One of the methods of the list is called to retrive
* the value of the key to be used and the object itself from the list entry is used as the
* objct. An empty <code>Map</code> is returned upon null input.
* Reflection is used to retrieve the key from the object instance and method name passed in.
*
* #param <K> The type of the key to be used in the map
* #param <V> The type of value to be used in the map and the type of the elements in the
* collection
* #param coll The collection to be converted.
* #param keyType The class of key
* #param valueType The class of the value
* #param keyMethodName The method name to call on each instance in the collection to retrieve
* the key
* #return A map of key to value instances
* #throws IllegalArgumentException if any of the other paremeters are invalid.
*/
public static <K, V> Map<K, V> asMap(final java.util.Collection<V> coll,
final Class<K> keyType,
final Class<V> valueType,
final String keyMethodName) {
final HashMap<K, V> map = new HashMap<K, V>();
Method method = null;
if (isEmpty(coll)) return map;
notNull(keyType, Messages.getString(KEY_TYPE_NOT_NULL));
notNull(valueType, Messages.getString(VALUE_TYPE_NOT_NULL));
notEmpty(keyMethodName, Messages.getString(KEY_METHOD_NAME_NOT_NULL));
try {
// return the Method to invoke to get the key for the map
method = valueType.getMethod(keyMethodName);
}
catch (final NoSuchMethodException e) {
final String message =
String.format(
Messages.getString(METHOD_NOT_FOUND),
keyMethodName,
valueType);
e.fillInStackTrace();
logger.error(message, e);
throw new IllegalArgumentException(message, e);
}
try {
for (final V value : coll) {
Object object;
object = method.invoke(value);
#SuppressWarnings("unchecked")
final K key = (K) object;
map.put(key, value);
}
}
catch (final Exception e) {
final String message =
String.format(
Messages.getString(METHOD_CALL_FAILED),
method,
valueType);
e.fillInStackTrace();
logger.error(message, e);
throw new IllegalArgumentException(message, e);
}
return map;
}
A Java 8 example to convert a List<?> of objects into a Map<k, v>:
List<Hosting> list = new ArrayList<>();
list.add(new Hosting(1, "liquidweb.com", new Date()));
list.add(new Hosting(2, "linode.com", new Date()));
list.add(new Hosting(3, "digitalocean.com", new Date()));
//example 1
Map<Integer, String> result1 = list.stream().collect(
Collectors.toMap(Hosting::getId, Hosting::getName));
System.out.println("Result 1 : " + result1);
//example 2
Map<Integer, String> result2 = list.stream().collect(
Collectors.toMap(x -> x.getId(), x -> x.getName()));
Code copied from:
https://www.mkyong.com/java8/java-8-convert-list-to-map/
You can leverage the streams API of Java 8.
public class ListToMap {
public static void main(String[] args) {
List<User> items = Arrays.asList(new User("One"), new User("Two"), new User("Three"));
Map<String, User> map = createHashMap(items);
for(String key : map.keySet()) {
System.out.println(key +" : "+map.get(key));
}
}
public static Map<String, User> createHashMap(List<User> items) {
Map<String, User> map = items.stream().collect(Collectors.toMap(User::getId, Function.identity()));
return map;
}
}
For more details visit: http://codecramp.com/java-8-streams-api-convert-list-map/
I like Kango_V's answer, but I think it's too complex. I think this is simpler - maybe too simple. If inclined, you could replace String with a Generic marker, and make it work for any Key type.
public static <E> Map<String, E> convertListToMap(Collection<E> sourceList, ListToMapConverterInterface<E> converterInterface) {
Map<String, E> newMap = new HashMap<String, E>();
for( E item : sourceList ) {
newMap.put( converterInterface.getKeyForItem( item ), item );
}
return newMap;
}
public interface ListToMapConverterInterface<E> {
public String getKeyForItem(E item);
}
Used like this:
Map<String, PricingPlanAttribute> pricingPlanAttributeMap = convertListToMap( pricingPlanAttributeList,
new ListToMapConverterInterface<PricingPlanAttribute>() {
#Override
public String getKeyForItem(PricingPlanAttribute item) {
return item.getFullName();
}
} );
Apache Commons MapUtils.populateMap
If you don't use Java 8 and you don't want to use a explicit loop for some reason, try MapUtils.populateMap from Apache Commons.
MapUtils.populateMap
Say you have a list of Pairs.
List<ImmutablePair<String, String>> pairs = ImmutableList.of(
new ImmutablePair<>("A", "aaa"),
new ImmutablePair<>("B", "bbb")
);
And you now want a Map of the Pair's key to the Pair object.
Map<String, Pair<String, String>> map = new HashMap<>();
MapUtils.populateMap(map, pairs, new Transformer<Pair<String, String>, String>() {
#Override
public String transform(Pair<String, String> input) {
return input.getKey();
}
});
System.out.println(map);
gives output:
{A=(A,aaa), B=(B,bbb)}
That being said, a for loop is maybe easier to understand. (This below gives the same output):
Map<String, Pair<String, String>> map = new HashMap<>();
for (Pair<String, String> pair : pairs) {
map.put(pair.getKey(), pair);
}
System.out.println(map);
If you use Kotlin, there is an example:
listOf("one", "two").mapIndexed { i, it -> i to it }.toMap()
public class EmployeeDetailsFetchListToMap {
public static void main(String[] args) {
List<EmployeeDetailsFetch> list = new ArrayList<>();
list.add(new EmployeeDetailsFetch(1L, "vinay", 25000F));
list.add(new EmployeeDetailsFetch(2L, "kohli", 5000000F));
list.add(new EmployeeDetailsFetch(3L, "dhoni", 20000000F));
//adding id as key and map of id and student name
Map<Long, Map<Long, String>> map1 = list.stream()
.collect(
Collectors.groupingBy(
EmployeeDetailsFetch::getEmpId,
Collectors.toMap(
EmployeeDetailsFetch::getEmpId,
EmployeeDetailsFetch::getEmployeeName
)
)
);
System.out.println(map1);
//converting list into map of Student
//Adding id as Key and Value as Student into a map
Map<Long, EmployeeDetailsFetch> map = list.stream()
.collect(
Collectors.toMap(
EmployeeDetailsFetch::getEmpId,
EmployeeDetailsFetch -> EmployeeDetailsFetch
)
);
for(Map.Entry<Long, EmployeeDetailsFetch> m : map.entrySet()) {
System.out.println("key :" + m.getKey() + " Value : " + m.getValue());
}
}
}