This question already has answers here:
Increment an Integer within a HashMap
(13 answers)
Closed 10 months ago.
I'm new to HashMaps, and I was wondering if there was a way to add values together if they have the same key.
For example, when I have the key 'a' and the value is 20 and later on I use the key 'a' again and the value is 10 the value should now be 30.
I don't know how I would check if the Value already is in the HashMap and then use the same value again. The adding part could be done with just a variable that copies the current value and adds the new one, I guess.
I am guessing you want a hashmap for character vs integer and want to add the integer to already present value in case the value is present.You can do something like below:
public hashMapImpl(char ch, int number){
Map<Character,Integer> map = new HashMap<>();
if(map.containsKey(ch)){
map.put(ch, map.get(ch)+number);
}
else{
map.put(ch,number);
}
}
Where ch will be your key and number will be something that you want to store at particular key.
you can use compute method to add/sum a value in case a key exists, or create a new entry in case it doesn't.
Map<String, Integer> map = new HashMap<>();
String myKey = "a";
Integer myValue = 10;
map.compute(myKey, (key, value) -> {
if (value == null)
return myValue;
else
return value + myValue;
}
);
System.out.println(map);
map.compute(myKey, (key, value) -> {
if (value == null)
return myValue;
else
return value + myValue;
}
);
System.out.println(map);
Outputs:
a={10}
a={20}
Of course, putting this compute logic inside a method will make you code cleaner :)
I will use an example class called HashMapExamle to explain this.
Inside the class I will create a HashMap called bigHashMap assuming that was your initial hashMap with prior data.
I also have a main method to call the method that will solve your problem. I have named the method bigHashMap. So for starters, i have initialized our prior HashMap named bigHashMap and initialized wit with some new key-value pairs.
I will printout the value of the HashMap. I will then add a value with the same key, in this case food with the value 15, by calling the hashMapValueAdd method I have created and passing the key(food) and value(15) to it.
The concept of the method is:
Check if the HashMap contains the key.
if it has it, it will get the value with that ky and add the new value to it. it will then replace the value at the key with the new value.
If the key is not found in the hashmap then the new key-value pair will just be inserted.
class HashMapExample {
private static HashMap<String, Integer> bigHashMap;
public static void main(String[] args) {
bigHashMap = new HashMap<>();
// Add test data
bigHashMap.put("food", 200);
bigHashMap.put("transport", 20);
bigHashMap.put("entertainment", 40);
System.out.println("Data before : \n" + bigHashMap);
hashmapValueAdd("food", 15);
System.out.println("Data after : \n" + bigHashMap);
}
private static void hashmapValueAdd(String key, int value) {
// Check if hashMap contains the given key
if (bigHashMap.containsKey(key)) {
// Get previous value with the same key
int valueWithSameKey = bigHashMap.get(key);
// Increment the value with incoming value
int newValue = valueWithSameKey + value;
// Put updated value into HashMap
// bigHashMap.put(key, +value);
bigHashMap.replace(key, newValue);
} else {
// Put the current key since it does not exist in the HashMap
bigHashMap.put(key, value);
}
}
}
I hope this solves your problem.
You can check out these HashMap explanations to get a better understanding.
Java HashMap - W3Schools
Java MAp - Jakob Jenkov
Java HashMap replace()
Update the Value Associated With a Key in a HashMap
Related
Why am i able to keep duplicate contains in Map as key,
i had heart about map is : it cat't contains duplicate keys
import java.util.LinkedHashMap;
import java.util.HashMap;
class LinkedHasMapDemo
{
#SuppressWarnings("unchecked")
public static void main(String[] args)
{
LinkedHashMap l = new LinkedHashMap();
//{116=kumar, 116=kumar, kumar=kumar, 117=Ram charan, 105=Yash}
//HashMap l = new HashMap();
//{116=kumar, 117=Ram charan, 116=kumar, kumar=kumar, 105=Yash}
l.put("116","kumar"); //key is String Object
l.put(116,"kumar"); //key is Integer Object
l.put("kumar","kumar");
l.put(117,"Ram charan");
l.put(105,"Yash");
System.out.println(l);
}
}
but is in this example i am able to keep duplicate keys in the both LinkedHashMap as well as in HashMap
You are right, a Map does not hold duplicate keys (this only applies to keys, values can be equal). If you put a value under an already added key the previous value will be overridden. Therefore consider the following example:
HashMap<String, Integer> map = new HashMap<>();
map.put("key", 1);
System.out.println(map.get("key")); // Outputs 1
System.out.println(map.size()); // Outputs 1
map.put("key", 2);
System.out.println(map.get("key")); // Outputs 2
System.out.println(map.size()); // Still outputs 1
The problem with your counter-example is that you actually don't have duplicates in your map.
You put 116 (an int or Integer after boxing) and "116" (a String). Since both are of different type the map differentiates them, they are different objects. Consider the following example
HashMap<Object, Integer> map = new HashMap<>();
map.put("116", 1);
System.out.println(map.size()); // Outputs 1
map.put(116, 2);
System.out.println(map.size()); // Now outputs 2
System.out.println("116".equals(116)); // Outputs false
In general you should never use raw-types, that is using HashMap without specifying the generic type to use, like HashMap<String, Integer>. If you don't specify anything it will use HashMap<Object, Object>. By that it allows every Object to be put into the map. In many cases you can and want to restrict this to a specific type only.
Try the following:
String s123="123";
Integer i123=123;
System.out.println(s123.hashCode());
System.out.println(i123.hashCode());
System.out.println(i123.equals(s123)); // you can try s123.equals(i123) too
You can even test it online, just copy/type these lines to http://www.javarepl.com/term.html - you will see that the String has a hashcode of 48690, the Integer has 123, and they do not consider equal to each other.
(Of course it works with 116 too just I did not have that number in front of me while typing this answer)
You don't have duplicates. Integer and String objects are not the same type so "116" and 116 are not equals and they have deferent Hash code
Objects that are equal must have the same hash code within a running process
in equals method if the type is not equals for both objects, it will return false, please check Integer equals implantation
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
also for Hash code they will not be equals in your case :
how String hash code is calculated :
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
And for Integer hash code is it the same integer value so in your case it will be 116 for Integer instance, so those will never be the same.
please avoid raw-types, that is using HashMap without specifying the generic type, please read this article what-is-a-raw-type-and-why-shouldnt-we-use-it for more details
So I have a hashmap which contains key as Strings and value as Integers of the count of those strings occurring in my Set
for eg I would have a hashMap as follows
Key Value
abcd 4 (meaning there are 4 duplicate strings of abcd in my Set defined someplace)
----- 13
b-b- 7
and so on..
Now what I am trying to do is remove all the empty strings entries from my HashMap. So in the above example I would want to remove all the empty strings with value 13. So my resulting HashMap would be
Key Value
abcd 4
b-b- 7
This is my code that tries to do the same. generateFeedbackMap() is function which returns the HashMap in consideration StringIterator is a class which I have defined which iterates over through each character of my Strings.
for(String key : generateFeedbackMap().keySet()) {
StringIterator it = new StringIterator(key);
int counter = 0;
while(it.hasNext()){
String nextChar = it.next();
if(nextChar.equals("-")){
counter++;
}
Iterator<Map.Entry<String, Integer>> mapIterator = generateFeedbackMap().entrySet().iterator();
if(counter >= key.length()){
while(mapIterator.hasNext()){
Map.Entry<String, Integer> entry = mapIterator.next();
if(entry.getKey().equals(key)){
mapIterator.remove();
}
}
}
}
}
So I increment the counter wherever I find a "-" character. When the counter equals my key string length which means it is an empty string, I remove it using Map Iterator but this does not remove the entry from my Map. What am I doing wrong?
generateFeedbackMap() makes it sound like you’re getting a copy of the underlying map, in which case removing a key from the copy won’t affect the underlying map. If you’re actually getting the map, then you should rename your method.
Regardless, the following would accomplish the same as your original code (but will only remove from the copy).
Map<String,Integer> feedbackMap = generateFeedbackMap();
for ( String key : feedbackMap.keySet() ) {
if ( key.matches("-+") ) {
feedbackMap.remove(key);
}
}
If you’re stuck getting a copy of the underlying map, then you do need to create your new helpfulMap. But you can still use a regular expression and other Map functions to speed things up:
Map<String,Integer> helpfulMap = new HashMap<>();
for ( Map.Entry<String,Integer> entry : generateFeedbackMap().entrySet() ) {
if ( ! entry.getKey().matches("-+") ) {
helpfulMap.put(entry.getKey(),entry.getValue());
}
}
Okay guys, I think I figured out a solution. I just copied all my current entries from oldMap to a new defined HashMap which would contain at least one letter in their keys. So essentially I got rid of all the removing and iterating over strings and just use another HashMap instead as below
Map<String, Integer> HelpfulMap = new HashMap<String,Integer>();
for(String key : generateFeedbackMap().keySet()) {
StringIterator it = new StringIterator(key);
while(it.hasNext()){
String nextChar = it.next();
if(!nextChar.equals("-")){
HelpfulMap.put(key, generateFeedbackMap().get(key));
}
}
}
I don't know what I was doing previously. I went for a good shower and came up with this idea and it worked. I love programming!
Thanks everyone for your inputs!
I found this program in my text book, which basically counts the occurence of each string in the String array tst.
public class Test {
private static HashMap<String, Integer> mp = new HashMap<String, Integer>();
public static void main(String[] args) {
String[] tst = new String[] { "ABC", "DEF", "DEF", "DEF","ABC", "DEF", "ABC" };
checkMap(tst);
}
public static void checkMap(String[] str) {
for (String st : str) {
if (!mp.containsKey(st)) {
mp.put(st, 1);
}
else {
Integer ct = mp.get(st);
if(ct!=null)
{
ct++;
mp.put(st, ct);
}
}
}
for (Map.Entry<String, Integer> entry : mp.entrySet()) {
System.out.println(entry.getKey() + " ocurrs " + entry.getValue()+ " times");
}
}
}
The output for the code is -
ABC ocurrs 3 times
DEF ocurrs 4 times
My question is in the if/else statement here -
if (!mp.containsKey(st)) {
mp.put(st, 1);
}
else {
Integer ct = mp.get(st);
if(ct!=null)
{
ct++;
mp.put(st, ct);
}
}
When we haven't put any entries inside the hashmap (the hashmap is empty), on what basis does this work? Apologies if this is a very basic question, but I found no answer anywhere online that explains this. I am confused with what is written in the if/else loop.
Also, this line here -
Integer ct = mp.get(st);
How can we get the value to which the key is mapped when infact the hashmap is actually empty? I am trying to relate this to an array - If you query elements of an array once its created, but not initialized, it throws a null pointer. Someone, please explain how this works for a hashmap. Once again, apologies for asking such a basic question.
Well, in this line you check whether the map contains a key
if (!mp.containsKey(st)) {
Since there is a ! before the expression, this means "if the map does not contain a key". After that, "then" block follows where you insert a key in the map with value 1 (since it does not exist).
Otherwise if the key does exist (the else block), you take the value for that key, increment it (ct++) and add it again to the map for the same key.
Let me just say that the null check (if(ct!=null)) is not necessary for this code.
General remark on this question:
How can we get the value to which the key is mapped when infact the hashmap is actually empty?
If you try to get something from the HashMap for a key that is not present in the map, the map returns null. That is true for any key you try to get from an empty map.
Can you please explain what this means though - Integer ct = mp.get(st);
map.get(key) returns a value that is stored for that key. The map itself is a collection of key-value pairs, which means: for each key there is one value in the map. So to get the value stored for that key you invoke map.get(key). If you store map.put("ABC", 10) the map will return 10 for map.get("ABC").
This is because of containsKey function checks if the hashMap contains particular key.
If the HashMap is mpty and you try to do a get on non existant key you will get a null value
st is get here by the for (String st : str) loop. It has nothing to do with the HashMap.
if (!mp.containsKey(st)) {
This tests if the HashMap does not contain the key st. If there are no items it obviously can not contain the key. Then in the else block it uses mp.get(st), which will now always succeed because it has been checked that mp contains st (actually, it does not not contain it).
The null check if (ct == null) is here because if for some reason the map contained null for the key in question. That however shouldn't be possible if the code only puts integers to the map and tests for the existence of the key, so the null check coulb be removed.
The test:
if (!mp.containsKey(st))
tests if there is no entry in the map by that key.
It is therefore logical that in the else branch, the entry exists and has a non null value... Which makes the ct == null test redundant.
And when the value exists, the code get()s the existing value, adds 1 to it (in fact it creates a new Integer but that's another story) and put()s back the new value.
Note that that code mixes autoboxing and non autoboxing. mp.put(st, 1) does autoboxing; behind the scenes it really does mp.put(st, new Integer(1)).
Similarly:
Integer ct = mp.get(st);
ct++;
is really:
Integer ct = mp.get(st);
Integer tmp = new Integer(ct.intValue() + 1);
ct = tmp;
The null check is not necessary. Either the key is contained in the map and its value is not null, or it is not contained in the map.
The reason we can be confident about the value never being null is that the map (and all its contents) is defined and used in the method, and there's no opportunity for a null to get it there.
Although the get() method will return null if passed a key that it doesn't contain, that will never happen with this code.
Anyway, the code is inelegant: All those lines can be expressed as one simple line:
mp.put(mp.containsKey(st) ? mp.get(st) + 1 : 1);
I am using a hashmap to populate a jtable. The user selects a row(s) and clicks a edit button. I am taking the value from the hashmap and placing it in a textarea. The user can make changes and then clicks another button. I have the new value and the key, but I am not sure how to write the changed value back to the right key in the hashmap.
THis is where I am writing the data out to the textarea
private void outputSelection() {
StringBuffer csb = new StringBuffer();
String s = "";
int[] row = selectTable.getSelectedRows();
for(int i = row.length-1; i >= 0; i--){
String check = (String) EdiMapTableModel.getMapInstance().getValueAt(i, EdiMapTableModel.getMapInstance().COMMENT_COL);
if (!isNullOrEmpty(check)) {
if (csb.length() > 0) {
csb.append("\n");
}
csb.append(check);
}
}
s = csb.toString();
csb.setLength(0);
output.append(s);
}
This is where I am trying to put the value back
private void inputSelection() {
String s = output.getText();
int[] row = selectTable.getSelectedRows();
for(int i = row.length-1; i >= 0; i--){
TCComponentItemRevision check = (TCComponentItemRevision) EdiMapTableModel.getMapInstance().getValueAt(i, EdiMapTableModel.getMapInstance().ITEMID_COL);
EdiMapTableModel.getMapInstance().commentBackMap(check, s);
repaint();
}
}
This is where I am trying to put it back in the map
public void commentBackMap(int row, TCComponentItemRevision id, String comment) {
if(model.containsKey(id)) {
model.put(id, comment);
}
fireTableDataChanged();
}// end commentBackMap()
I know containsKey is not right above. id is the key value
Do I need to iterate through the hashmap looking for a match? Don't know if it matters but it is a linkedhashmap instead of a hashmap
According to the HashMap#put documentation:
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
So all you have to do is call put with the same key and the new value, it will do the replacement for you.
This also applies to LinkedHashMap because it inherits the put method from HashMap.
If you want to maintain the location of your map entry, you can't put it again since that's going to move it to the end of the LinkedHashMap. You'll need a holder object, say an Object[1], where you'll replace its member without putting the map entry again.
Or maybe reevaluate your choice of LinkedHashMap.
I have an hashmap declared as
private HashMap testMessages = null;
I will be storing string values in both key and value part of the hashmap retrieved from oracle table.
I am not concerned about the hashmap keys. I want to retrieve the hashmap values alone and check whether string variable filename is prefixed with one of the hash map value and return true if it's same. I want to ensure that hash map values are not null and empty.
function (string filename)
{..
loop thru hashmap values
check whether the variable file name is prefixed with one of the hashmap values if so
return true
otherwise
return false
}
hashmap example:
key1,prod
key2,test
key3,dummy
filename example:
test123_20012010.csv
should return true since the file name is prefixed with one of the hashmap values
How can i do it?
for (String prefix : map.values()) {
if (filename.startsWith(prefix)) {
return true;
}
}
return false;
It should be noted that this is linear time in the number of entries in the map in the worst case. If you have multiple filename that you want to do the check for, it's much better to preprocess the prefixes and build something like a patricia trie and other fast dictionary-like data structures.
Here's a brute force approach to iterate over the hash map values and check whether filename begins with the value.
// generics version
private HashMap<String, String> testMessages = buildMap();
for (String v : testMessages.values()) {
if (filename.startsWith(v) {
// found a map value that starts the file name
}
}
// alternative non-generics version
private HashMap testMessages; // assigned somewhere
for (Object v : testMessages.values()) {
if (filename.startsWith((String) v) {
// found a map value that starts the file name
}
}
leeched from leepoint.net
public static void iterate_over_hashmap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
}
You have to treat each entry as a key/value pair and iterate over those as a single entity. Then you cast it into Map.Entry and then you can read both separately
function(String fileName)
{
for(String value : hashMap.values())
{
if(fileName.startsWith(value))
return true;
}
return false;
}