Sorting Collection<V> and Set<K> - java

I'm having an issue sorting the values and keys from a map from least to greatest(integers and String's).
Here are the two methods, first the method for values:
public Collection<V> values(){
Collection<V> coll = new LinkedList<V>();
for(int i = 0; i < table.length; i++){
if(table[i] != null){
for(Entry<K, V> nextItem : table[i]){
if(nextItem.value != null){
if(!coll.contains(nextItem.value)){
coll.add(nextItem.value);
}
}
}
}
}
return coll;
}
Expected Output:
120 123 404 911 999
My Output (basically keeps order of wherever it was in the map):
911 999 123 120 404
The above method is used with dot notation for a hashTableChain (an array who's keys are sorted by their hashCode where the indices of the array are linkedLists), it returns the values for the given map. I tried sorting it with Collections.sort(coll) however this requires a List which is incompatible with Collection to my knowledge. Is there something compatible with Collection that is either already sorted or can be sorted in an easy way?
The method for the key's:
public Set<K> keySet(){
Set<K> coll = new HashSet<K>();
for(int i = 0; i < table.length; i++){
if(table[i] != null){
for(Entry<K, V> nextItem : table[i]){
coll.add(nextItem.key);
}
}
}
return coll;
}
Expected Output:
ABC ACTG HTML LOL OMG XYZ
My Output (basically keeps order of wherever it was in the map):
XYZ ABC ACTG HTML LOL OMG
Again I tried Collections.sort(coll) to no avail and couldn't find any way to sort it.
I'm fairly new to java and I'm sure I'm overlooking something, after searching the web for a while I figured I'd just ask.
Thanks in advance and I very much appreciate the help.
Added at request:
private static class Entry<K, V> implements Map.Entry<K, V> {
/** The key */
private K key;
/** The value */
private V value;
/**
* Creates a new key-value pair.
* #param key The key
* #param value The value
*/
public Entry(K key, V value) {
this.key = key;
this.value = value;
}

About first example you can use a List<V> for variable coll:
public Collection<V> values(){
List<V> coll = new LinkedList<V>();
// do stuff
Collections.sort(coll);
return coll;
}
and is correct, because LinkedList implements List. You have to choice the supertype compatible with your needs; if you need to return a sorted list, you can use a List in your function, sort them and return the list as Collection.
In second example the same, but use a
Set<K> coll = new TreeSet<K>();
TreeSet implements SortedSet, A Set that further provides a total ordering on its elements.

What you call a Collection happens to be a List in 100% of the cases. You just need to tell the compiler this by either:
Casting (List<V>)coll before calling sort, or
Changing the declaration List<V> coll= new LinkedList<V>() ;
If you have 123 as a value two times, I think it's correct it appears two times in values()'s result.
In the second case, I'd recommend to use a SortedSet instead of a HashSet.
Please consider the following code:
public class Sample<K extends Comparable<K>,V extends Comparable<V>> {
public static class Entry<A,B> implements Map.Entry<A,B> {
A key;
B value;
public Entry(A key,B value) {
this.key= key ;
this.value= value ;
}
public A getKey() {
return this.key ;
}
public B getValue() {
return this.value ;
}
public B setValue(B value) {
return this.value= value ;
}
}
LinkedList<Entry<K,V>>[] table;
public Collection<V> values(){
List<V> coll= new LinkedList<V>() ;
for(LinkedList<Entry<K, V>> e: table ) {
if( e != null ) {
for(Entry<K, V> nextItem : e ) {
if( nextItem.value != null ) {
coll.add(nextItem.value);
}
}
}
}
Collections.sort(coll);
return coll;
}
public Set<K> keySet(){
Set<K> coll= new TreeSet<K>() ;
for(LinkedList<Entry<K, V>> e: table ) {
if( e != null ) {
for(Entry<K, V> nextItem : e ) {
coll.add(nextItem.key);
}
}
}
return coll;
}
public static void main(String... args) {
Sample<String,Integer> test= new Sample<String,Integer>();
test.table= (LinkedList<Entry<String,Integer>>[])new LinkedList[1024] ;
test.table[467]= new LinkedList<Entry<String,Integer>>() ;
test.table[467].add( new Entry("XYZ",999) );
test.table[467].add( new Entry("ABC",123) );
test.table[678]= new LinkedList<Entry<String,Integer>>() ;
test.table[678].add( new Entry("ACTG",404) );
test.table[678].add( new Entry("HTML",120) );
test.table[678].add( new Entry("ACTG",404) );
test.table[678].add( new Entry("LOL",123) );
test.table[ 2]= new LinkedList<Entry<String,Integer>>() ;
test.table[ 2].add( new Entry("OMG",911) );
System.out.println( test.values() );
System.out.println( test.keySet() );
}
}
If you expect to create a generic class in which the values of the parametric types are going to be sorted, then they need to implement interface Comparable. And if they need to implement interface Comparable, then you need to say so when declaring your class. That's why the K extends Comparable<K> and V extends Comparable<V> while declaring Sample. This is particularly important when you call Collections.sort or you instantiate TreeSet. Both require that the parameters/parametric types are Comparables (or subtypes of).
The result of the test case I added are correct:
[120, 123, 123, 404, 404, 911, 999]
[ABC, ACTG, HTML, LOL, OMG, XYZ]
respectively.

Related

What is the main difference between LinkedList, HashSet and HashMap?

Well, you don't mind I will write my "test" project;
First of all I had created class that implements AbstractMap.
public class TestClass <K, V> extends AbstractMap <K, V>
TestClass has the private LinkedList that take as a parameter (It is another class that implements Map.Entry:
private int size = 1000;
private LinkedList <InfoClass <K, V>> [] array = new LinkedList [size];
After, I had created the method that checks and replaces duplicates:
public V put (K key, V value){ // Void doesn't work, therefore we need to return any value;
V temp = null;
boolean found = false;
int index = Math.abs(key.hashCode()) % size;
if (array[index] == null)
array[index] = new LinkedList <InfoClass <K, V>> (); // If the specified member of array is null, create new member;
LinkedList <InfoClass <K, V>> list = array[index];
InfoClass <K, V> info = new InfoClass <K, V> (key, value);
ListIterator <InfoClass <K, V>> it = list.listIterator();
while (it.hasNext()){
InfoClass<K, V> temp2 = it.next(); // Create a temp instance;
if (temp2.getKey().equals(key)){ // If there is a duplicate of value, just replace by new one;
found = true;
temp = temp2.getValue();
it.set(info);
break;
}
}
if (!found) // if there is not a duplicate, add new one;
array[index].add(info);
return temp;
}
Next method returns a value, otherwise this returns null if a member of array doesn't exist:
public V get (Object key){ // The parameter K doesn't work;
int index = Math.abs(key.hashCode()) % size;
if (array[index] == null)
return null;
else
for (InfoClass <K, V> info : array[index])
if (info.getKey().equals(key))
return info.getValue();
return null;
}
This method forms a set of AbstractMap:
public Set<java.util.Map.Entry<K, V>> entrySet() {
Set <Map.Entry<K, V>> sets = new HashSet <Map.Entry<K, V>> ();
for (LinkedList <InfoClass<K, V>> temp1 : array){
if (temp1 == null)
continue;
else{
for (InfoClass<K,V> temp2 : temp1)
sets.add(temp2);
}
}
return sets;
}
Ok, create new object in main method:
public static void main (String [] args){
TestClass <Integer, String> TC = new TestClass <Integer, String> ();
TC.putAll(CollectionDataMap.newCollection(new Group.Ints(), new Group.Name(), 10));
System.out.println(TC);
System.out.println(TC.get(1));
TC.put(1, "Hello this world");
System.out.println(TC);
}
Hope I explained correctly. I have a question, what is difference between LinkedList and LinkedHashMap (HashMap) if they work the same way?
Thank you very much!
LinkedList can contain the same element multiple times if the same element is added multiple times.
HashSet can only contain the same object once even if you add it multiple times, but it does not retain insertion order in the set.
LinkedHashSet can only contain the same object once even if you add it multiple times, but it also retains insertion order.
HashMap maps a value to a key, and the keys are stored in a set (so it can be in the set only once). HashMap doesn't preserve insertion order for the key set, while LinkedHashMap does retain insertion order for the keys.

How to take separate data from LinkedHashMap<String, Double> in Java

I used LinkedHashMap<String, Double> . I want to take separate values from it. If it is Array we can use .get[2] ,.get[5] etc. for take 2nd and 5th value. But for LinkedHashMap<String, Double> how to do it. I used following code. But it print all the values contained in LinkedHashMap<String, Double>. I need to take separately.
Set set = mylist.entrySet();
Iterator i = set.iterator();
while(i.hasNext()) {
Map.Entry me1 = (Map.Entry)i.next();
System.out.print(me1.getKey());
System.out.println(me1.getValue());
You may use the LinkedHashMap#get(Object key) method
Which will return the value corresponding to the key parameter. Since your keys are String, you can not use an int to retrieve them.
Example
If your LinkedHashMap contains ["key", 2.5], calling
System.out.println(lnkHashMap.get("key"));
will print
2.5
Addition
If you're using java-8, there is a workaround using a Stream object.
Double result = hashmap.values()
.stream()
.skip(2)
.findFirst()
.get();
This will skip the two first values and get to the third one directly and return it.
If not, here is a solution
public <T> T getValueByIndex (Map<? extends Object, T> map, int index){
Iterator<T> it = map.values().iterator();
T temp = null;
for (int i = 0 ; i < index ; i++){
if (it.hasNext()){
temp = it.next();
} else {
throw new IndexOutOfBoundsException();
}
}
return temp;
}
It could be the case that you are using the wrong data structure for your purpose.
If you look closely to the LinkedHashMap API you will notice that it is indeed a Map and the only way to access a previously stored value is by providing its key.
But if you really think you need to access the ith value of the LinkedHashMap according to its insertion-order (or access-order) you can use a simple utility method like the following:
Java 8 Solution
private static <K, V> Optional<V> getByInsertionOrder(LinkedHashMap<K, V> linkedHashMap, int index) {
return linkedHashMap.values().stream()
.skip(index)
.findFirst();
}
Java 7 Soution
private static <K, V> V getByInsertionOrder(LinkedHashMap<K, V> linkedHashMap, int index) {
if (index < 0 || index >= linkedHashMap.size()) {
throw new IndexOutOfBoundsException();
}
Iterator<Entry<K, V>> iterator = linkedHashMap.entrySet().iterator();
for (int i = 0; i < index; i++) {
iterator.next();
}
return iterator.next().getValue();
}

how can i get the number of same-value-more-than-once occurrences for a HashMap in Java?

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(); }
}

Sorting HashMap<?,?> by key

hello
I need to implement a method that receives a HashMap and sorts (mergeSort) it's values by key (without using TreeMap, SortedMap or Collections.Sort or use any sort solutions from JAVA Packages).
my problem is dealing with the wildcard Types...
this is my implementation (that returns compilation errors because of wildcards use)
public HashMap<?, ?> mergeSort(HashMap<?, ?> map) {
if (map.size() < 1) {
return map;
}
// rounds downwards
int middle = map.size() / 2;
int location = 0;
HashMap<?,?> mapLeft = new HashMap<?, ?>();
HashMap<?,?> mapRight = new HashMap<?, ?>();
// splitting map
for (Iterator<?> keyIter = map.keySet().iterator(); keyIter.hasNext();) {
if (location < middle) {
mapLeft.put(keyIter, map.get(keyIter));
} else {
mapRight.put(keyIter, map.get(keyIter));
}
location++;
}
// recursive call
mapLeft = mergeSort(mapLeft);
mapRight = mergeSort(mapRight);
return merge(mapLeft, mapRight);
}
public HashMap<?, ?> merge(HashMap<?, ?> mapLeft, HashMap<?, ?> mapRight) {
HashMap<?, ?> result = new HashMap<?, ?>();
Iterator<?> keyLeftIter = mapLeft.keySet().iterator();
Iterator<?> keyRightIter = mapRight.keySet().iterator();
String keyLeft;
String keyRight;
while (keyLeftIter.hasNext()) {
keyLeft = keyLeftIter.next();
while (keyRightIter.hasNext()) {
keyRight = keyRightIter.next();
if (keyLeft.compareTo(keyRight) < 0) {
result.put(keyLeft, mapLeft.get(keyLeft));
keyLeft = keyLeftIter.next();
} else {
result.put(keyRight, mapRight.get(keyRight));
keyRight = keyRightIter.next();
}
}
}
return result;
}
I appreciate your help!
If all you have to do is meet a method contract, you can do this.
public HashMap<?, ?> mergeSort(HashMap<?, ?> map) {
return new LinkedHashMap(new TreeMap(map));
}
This will sort the keys and return a subclass of HashMap. The design of this method is broken, but sometimes you can't change things.
If you are sorting a map, you should be using a SortedMap like TreeMap. hashmap doesn't retain an order so using it for a merge sort is not possible. Using a merge sort for a TreeMap is redundant.
You cannot assume that ? is a Comparable. You can write something like.
public static <K extends Comparable<K>, V> SortedMap<K,V> sort(Map<K,V> map) {
return new TreeMap<K, V>(map);
}
As you can see this is shorter and simpler than your approach. Is this homework? Do you reall need to use a merge sort?
The problem you have is that you cannot return a HashMap as it doesn't keep the order, adn you cannot return a TreeMap because it will sort the keys for you making anything else you redundant. For this task you can only return a LinkedHashMap as it does retain order, without doing the sorting for you.
here is an example using LinkedHashMap. Note it doesn't create copies of Maps as it goes, it creates a single array and merge sorts portions of it until its completely sorted.
Note: I use TreeMap as a SortedMap to show its sorted correctly. ;)
public static void main(String... args) throws IOException {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0;i<100;i++)
map.put((int)(Math.random()*1000), i);
System.out.println("Unsorted "+map);
System.out.println("Sorted "+sort(map));
final String sortedToString = sort(map).toString();
final String treeMapToString = new TreeMap<Integer, Integer>(map).toString();
if (!sortedToString.equals(treeMapToString))
System.out.println(sortedToString+" != \n"+treeMapToString);
}
public static <K extends Comparable<K>, V> Map<K, V> sort(Map<K, V> map) {
return mergeSort(map);
}
// a very bad design idea, but needed for compatibility.
public static <K extends Comparable<K>, V> HashMap<K, V> mergeSort(Map<K, V> map) {
Map.Entry<K, V>[] entries = map.entrySet().toArray(new Map.Entry[map.size()]);
mergeSort0(entries, 0, entries.length);
HashMap<K, V> ret = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : entries)
ret.put(entry.getKey(), entry.getValue());
return ret;
}
private static <K extends Comparable<K>, V> void mergeSort0(Map.Entry<K, V>[] entries, int start, int end) {
int len = end - start;
if (len < 2) return;
int mid = (end + start) >>> 1;
mergeSort0(entries, start, mid);
mergeSort0(entries, mid, end);
// merge [start, mid) and [mid, end) to [start, end)
for(int p = start, l=start, r=mid; p < end && l < r && r < end; p++) {
int cmp = entries[l].getKey().compareTo(entries[r].getKey());
if (cmp <= 0) {
l++;
// the entry is in the right place already
} else if (p != r) {
// we need to insert the entry from the right
Map.Entry<K,V> e= entries[r];
// shift up.
System.arraycopy(entries, p, entries, p+1, r - p);
l++;
// move down.
entries[p] = e;
r++;
}
}
}
prints
Unsorted {687=13, 551=0, 2=15, 984=3, 608=6, 714=16, 744=1, 272=5, 854=9, 96=2, 918=18, 829=8, 109=14, 346=7, 522=4, 626=19, 495=12, 695=17, 247=11, 725=10}
Sorted {2=15, 96=2, 109=14, 247=11, 272=5, 346=7, 495=12, 522=4, 551=0, 608=6, 626=19, 687=13, 695=17, 714=16, 725=10, 744=1, 829=8, 854=9, 918=18, 984=3}
Like other commenters I would suggest reading up on the subject of generics in Java. What you did in merge is using wildcards on the result HashMap
HashMap<?, ?> result = new HashMap<?, ?>();
When you put wildcards on it, you are basically saying "I will only be reading from this". Later on you trying to push something in
result.put(keyLeft, mapLeft.get(keyLeft));
The compiler will say "Hey, you just told me you would only read and now you want to put something in... FAIL
Then it generates your compile time errors.
Solution
Don't put wildcards on collections you will modify.
Why are you always using ?. Give the kids a name like Key or Value.
Edit: You should work through this tutorial fist: Lesson: Generics
Here is a method that sorts a Map by its keys. It makes use of the Collections.sort(List, Comparator) method.
static Map sortByKey(Map map) {
List list = new LinkedList(map.entrySet());
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable) ((Map.Entry) (o1)).getKey())
.compareTo(((Map.Entry) (o2)).getKey());
}
});
Map result = new LinkedHashMap();
for (Iterator it = list.iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry)it.next();
result.put(entry.getKey(), entry.getValue());
}
return result;
}

Java Hashmap: How to get key from value?

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;
}

Categories