I have a HashMap as below (assuming it has 10,0000 elements)
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("John","1");
hm.put("Alex","2");
hm.put("Mike","3");
hm.put("Justin","4");
hm.put("Code","5");
==========================
Expected Output
==========================
Key = John",Value = "1"
Key = Alex",Value = "2"
Key = Mike",Value = "3"
Key = Justin",Value = "4"
Key = Code",Value = "5"
===========================
I need Java code to prevent Addition of Duplicate <Key,Value> Pairs in HashMap such
that below conditions are staisfied.
1> hm.put("John","1"); is not accepted/added again in the Map
2> hm.put("John","2"); is not accepted/added again in the Map
Hope its clear.
Java code provided will be appreciated.(generic solution needed since i can add any duplicate to the existing map)
You can wrap HashMap in a class, which delegates put, get, and other methods you use from HashMap. This method is wasteful but safe, since it doesn't depend on the internal implementation of HashMap, AbstractMap. The code below illustrates put, get delegating:
public class Table {
protected java.util.HashMap<String, Integer> map =
new java.util.HashMap<String, Integer>();
public Integer get(String key) { return map.get(key); }
public Integer put(String key, Integer value) {
if (map.containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return map.put(key, value);
}
}
// other methods goes here
}
Another option is to make a class which extends HashMap, and depend on its internal implementation. Java 1.6 sources shows that put is called only in putAll in HashMap, so you can simply override put method:
public class Table extends java.util.HashMap<String, Integer> {
public Integer put(String key, Integer value) {
if (containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return super.put(key, value);
}
}
}
Another option is similar to the first, and can make an utility method in your class which contains the HashMap instance and call that method wherever you need put something to your map:
public final Integer putToMap(String key, String value) {
if(this.map.containsKey(key)) {
return value;
} else {
return this.map.put(key, value);
}
}
This is an "inline" equivalent of checking manually.
I note that you clarify the question by suggesting you might have "100000000 elements". You still won't have duplicates in the HashMap, because, as two other posters have pointed out, you can't get duplicate keys in a Map. I'm still not sure we understand the question, though, as it's not at all clear how you expected to generate the block titled "Output", or what you intend to do with it.
This may be old question but I thought to share my experience with this. As others pointed out you can't have the same element in a HashMap. By default HashMap will not allow this but there are some cases that you could end up with two or more elements are almost alike that you do not accept but HashMap will. For example, the following code defines a HashMap that takes an array of integers as a key then add :
HashMap<int[], Integer> map1 = new HashMap<>();
int[] arr = new int[]{1,2,3};
map1.put(arr, 4);
map1.put(arr, 4);
map1.put(arr, 4);
At this point, the HashMap did not allow dublicating the key and map1.size() will return 1. However, if you added elements without creating the array first things will be different:
HashMap<int[], Integer> map2 = new HashMap<>();
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
This way, the HashMap will add all the three new elements so the map2.size() will return 3 and not 1 as expected.
The explanation is that with the first map I created the object arr once and tried to add the same object 3 times which HashMap does not allow by default so only the last usage will be considered. With the second map, however, evey time I recreate a new object on the stack. The three objects created are different and separated thought the three of them have the same data but they are different. That's why HashMap allowed them as different keys.
Bottom line, you don't need to prevent HashMap from adding dublicated keys because it won't by design. However, you have to watch out how you define these keys because the fault may be on your side.
List<String> keys = new ArrayList<String>(); (1000000)
List<String> values = new ArrayList<String>(); (1000000)
Map<String, String> map = new HashMap<String, String>();
int i =0;
for(String key : keys){
String returnedValue = map.put(key, values.get(i));
if(returnedValue!=null){
map.put(key, returnedValue);
system.out.println("Duplicate key trying to be entered with new value so reverting the duplicate key ="+key+"new Value"+values.get(i));
}
}
Unfortunately, it is the way that Map works.
The easiest workaround is to remove all pre existed keys and their values by calling hm.remove() first! like this:
for (String name : names) {
hm.remove(name);
hm.put(name,uri.getQueryParameter(name));
}
And if you don't use a for loop just call it like this:
hm.remove("John");
hm.put("John","1");
hm.remove("Alex");
hm.put("Alex","2");
hm.remove("Mike");
hm.put("Mike","3");
And so on ...
see even if u write same key values multiple times you will just have unique set of pairs. Check that by either iterating or by doing hm.size();
if(hm.put("John","1") != null)
{
// "John" was already a key in the map. The sole value for this key is now "1".
}
List<Object> yourElements = new ... // 10000000
for(Object O : yourElements) {
if(myMap.get(O.key)==null) {
myMap.put(O.key,O);
}
}
Related
How can I check if there is a value using the fields of a given value? And put new one?
In ConcurrentHashMap, cause I have N threads.
Here is an example of what I want. However, it is not thread-safe.
Map<Integer, Record> map = new ConcurrentHashMap<>();
// it works, but I think it's unsafe
int get(Object key) {
for (Map.Entry<Integer, Record> next : map.entrySet()) {
if (next.getValue().a == key) {
return next.getValue().b;
}
}
int code = ...newCode();
map.put(code, new Record(...))
return code;
}
record Record(Object a, int b) {
}
What you're suggesting would defeat the purpose of using a HashMap since you're iterating through the Map instead of retrieving from the Map.
What you should really do is create a new Map where the field in Record.a is the Key and the field in Record.B is the value (or just the whole Record). Then just update your logic to insert into both Maps appropriately.
I have a hashamp with only one key (and a value). Lets say I don't know the key or value of that one key. Is there a way to find it? This may sound dumb but since there is only ONE key, then would there be a way to get that key.
For a single key map just do the following:
Map<String,String> map = Map.of("A","B");
System.out.println(map.keySet().iterator().next());
prints
A
For a more populated map you can do the following:
You can get the keySet() of the map via map.keySet() and iterate thru that.
If you want to try and find a particular key associated with a value you can
get the entrySet() of the map and do something like this:
String targetVal = "some value";
for (Entry<String,String> e : map.entrySet()) {
if (e.getValue().equals(targetVal)) {
System.out.println(e.getKey());
// or
System.out.println(e);
// keep iterating since multiple keys can
// map to the same value.
}
}
You can get all of your keys with hash_map.keySet()
https://www.geeksforgeeks.org/hashmap-keyset-method-in-java/
Yes, you can use iterators, which enable you to iterate over any Collection (or Map's entrySet()):
public class Main {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("First", "Entry");
System.out.println(map.entrySet().iterator().next());
}
}
This prints: First=Entry, where First is the key and Entry is the value.
hashMapObj.entrySet().iterator().next();
is the answer to your question.
I've created List of Maps using the following
List<Map<Object, String>> postModel = new ArrayList<>();
I just started out with java and not able to figure out how to retrieve the individual Map key value.
It would be great if you could point me to some documentation.
Thanks
You can loop through every Map in the List and get the entrySet of each, something like this:
for(Map<Object, String> map : postModel){
for(Map.Entry<Object, String> entry : map.entrySet(){
entry.getKey();
entry.getValue();
// you can add the condition you want here
// and return the pair key-value after wrapping this with a method
}
}
Moreover, if you want a particular Key itself in the Map at a particular index in the List, you can create a method and use the keySet like this for example:
Object getKey(int index, String key){
for(Object k : postModel.get(index).keySet()){
if(k.toString().equals(key)){
return k;
}
}
return null;
}
Lastly if you want only the Value of a given Key of a particular Map, you simply get it like this:
String getValue(int index, Object key){
postModel.get(index).get(key); // or you really don't need to wrap it
}
This question already has answers here:
Are mutable hashmap keys a dangerous practice?
(10 answers)
Closed 6 years ago.
What I did was simple: I would like to creat a HashMap<Pair, ArrayList<Integer>> with Pair as the key and ArrayList<Integer> as the value. The Pair is self-defined class containing elements l (left) and r (right).
At first, I did this as following:
Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");
Pair<String, Integer> aPair = new Pair<>(" ", 1); // HERE will be changed!
for (String aString: stringList) {
aPair.setLeft(aString);
if (!hashmap.containsKey(aPair)){
hashmap.put(aPair, new ArrayList<Integer>());
}
hashmap.get(aPair).add(1);
}
for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
But the output is:
a 1 [1]
a 1 [1]
a 1 [1, 1]
However, if I changed the above code into the following:
Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");
for (String aString: stringList) {
Pair<String, Integer> aPair = new Pair<>(aString, 1); // HERE changed!
if (!hashmap.containsKey(aPair)){
hashmap.put(aPair, new ArrayList<Integer>());
}
hashmap.get(aPair).add(1);
}
for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
The change made was putting the declaration of Pair<String, Integer> aPair into the for-loop. The results new are what I wanted as following:
c 1 [1]
b 1 [1]
a 1 [1, 1]
Why it is like this? Here is a similar question. But it is still different.
EDIT: as mentioned in the comments below by #Eran, the self-defined Pair override the methods hashCode() and equals()
#Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
#Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair<?, ?> pairo = (Pair<?, ?>) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
If an object’s hashCode() value can change based on its state, then we
must be careful when using such objects as keys in hash-based
collections to ensure that we don’t allow their state to change when
they are being used as hash keys. All hash-based collections assume
that an object’s hash value does not change while it is in use as a
key in the collection. If a key’s hash code were to change while it
was in a collection, some unpredictable and confusing consequences
could follow. This is usually not a problem in practice — it is not
common practice to use a mutable object like a List as a key in a
HashMap.
From this answer
You're treading in dangerous waters, since your keys are mutable, read this why it is not a good idea - Are mutable hashmap keys a dangerous practice?.
Well, your example alone shows why it isn't a good idea. You add 1 instance of key in your map, and then modify it, effectively modifying all key-value pairs in your hashmap.
Your first snippet doesn't work because you are mutating the same Pair instance that already serves as a key in the HashMap. This allows the same Pair instance to appear as a key in multiple entries of the HashMap (since the new hashCode computed after you modified the Pair instance is mapped to a new bucket of the HashMap that doesn't contain any entry) and effectively break the HashMap.
You shouldn't mutate an instance that serves as key of a HashMap (unless you remove it from the HashMap before updating it and put the updated version in the Map later).
In first code snippet, you are actually using the same key object for every entry of map. You just modifying it's left value, but it still points to the same memory address. Map needs to have unique keys (every key must point to different memory address) that's why you need to put new instance of pair for each map entry.
Based on the following code snippet :
Hashtable balance = new Hashtable();
Enumeration names;
String str;
double bal;
balance.put("Zara", new Double(3434.34)); //first entry for Zara
balance.put("Mahnaz", new Double(123.22));
balance.put("Zara", new Double(1378.00)); //second entry for Zara
balance.put("Daisy", new Double(99.22));
balance.put("Qadir", new Double(-19.08));
System.out.println(balance.entrySet());
.
Output : [Qadir=-19.08, Mahnaz=123.22, Daisy=99.22, Zara=1378.0]
Why isn't chaining happening here? When I re-enter with Zara as key the old value is overwritten. I expected it to be added at the end of the Linked List at Zara".hashcode() index.
Does Java use separate chaining only for collision handling?
If I can't use chaining( as I'v tried above) please suggest a common method to do so.
Does Java use separate chaining only for collision handling?
Yes. You can only have one entry per key in a Hashtable (or HashMap, which is what you should probably be using - along with generics). It's a key/value map, not a key/multiple-values map. In the context of a hash table, the term "collision" is usually used for the situation where two unequal keys have the same hash code. They still need to be treated as different keys, so the implementation has to cope with that. That's not the situation you're in.
It sounds like you might want a multi-map, such as one of the ones in Guava. You can then ask a multimap for all values associated with a particular key.
EDIT: If you want to build your own sort of multimap, you'd have something like:
// Warning: completely untested
public final class Multimap<K, V> {
private final Map<K, List<V>> map = new HashMap<>();
public void add(K key, V value) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList();
map.put(key, list);
}
list.add(value);
}
public Iterable<V> getValues(K key) {
List<V> list = map.get(key);
return list == null ? Collections.<V>emptyList()
: Collections.unmodifiableList(list);
}
}
Quote from the documentation of Map (which Hashtable is an implementation of):
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
(emphasis mine)
The documentation of put() also says:
If the map previously contained a mapping for the key, the old value is replaced by the specified value
So if you want multiple values associated with a key, use a Map<String, List<Double>> instead of a Map<String, Double>. Guava also has a Multimap, which does what you want without having to deal with Lists explicitely as with a Map<String, List<Double>>.