HashMap delete entry AND position - java

I'm just working with HashMaps and now it pops up a question I actually can't answer by myself...
In my HashMap there are some entries. I'm now searching through all the entries for a certain value. If that value is found It delete it using hashmap.remove();. But I don't "only" want to delete the entry but the whole "position" of the HashMap so that there is no blank space between it. In the end the HashMap shouldn't have any value anymore (I think it will be null then, won't it?)
Is there any possible way to do so?
That's what I got so far but it only deletes the entry not the whole position...
for (Entry<Integer, String> entry : myMap.entrySet()) {
if (entry.getValue().contains("EnterStringHere")) {
myMap.remove(entry);
}
}

This is wrong
for (Entry<Integer, String> entry : myMap.entrySet()) {
if (entry.getValue().contains("EnterStringHere")) {
myMap.remove(entry); // you should pass the key to remove
}
}
But you can't use this way to remove element. You will get ConcurrentModificationException.
You can try this way using iterator to remove element while iterating.
Map<Integer,String> map=new HashMap<>();
map.put(1,"EnterStringHere");
map.put(2,"hi");
map.put(3,"EnterStringHere");
Iterator<Map.Entry<Integer,String>> iterator=map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<Integer,String> entry=iterator.next();
if(entry.getValue().equals("EnterStringHere")){
iterator.remove();
}
}
System.out.println(map);
Out put:
{2=hi}
You really need to see HashMap#remove()

You cannot remove the entry object from a Map. The remove method expects key.
Instead you can try the below:-
Iterator<Entry<Integer, String>> itr = myMap.entrySet().iterator();
while(itr.hasNext()) {
Entry<Integer, String> entry = itr.next();
if (entry.getValue().contains("EnterStringHere"))
{
itr.remove();
}
}
Also you cannot directly structurally modify a Map while iterating else you will get ConcurrentModification Exception. To prevent this you need to delete using the remove method on the iterator as shown in above code.

Let's say you got a Map<Key,Value> size of 10 and you want to remove 8th key value pair in current Map. What happen is Map become the size of 9 and there will be another key value pair in 8th position.
You can't to beyond that with remove(). You can't remove the position.
But when you use Map.get(removed_key) you will get null since there is no key there now.
Eg:
Map<String,Integer> map=new HashMap<>();
map.put("a",1);
map.put("b",2);
map.put("c", 3);
System.out.println("size of the map "+map.size() +" map is "+map);
map.remove("b");
System.out.println("size of the map "+map.size() +" map is "+map);
System.out.println(map.get("b"));
Out put:
size of the map 3 map is {b=2, c=3, a=1}
size of the map 2 map is {c=3, a=1}
null // you are getting null since there is no key "b"
Adding this to provide answer to your comment,If you want to check whether map is empty. simply use map.isEmpty()

Understanding how HashMap works here Link.
Also see java doc here link.
If you want to set pack your hashmap try to check size of the map then delete one then check size again for example.
hashmap.size(); => 10
hashmap.remove(obj);
hashmap.size() => 9
this means the hashmap is packed and will not have any empty entry. At the end hashmap will automatically will not contain any value in it

Because after a certain time I need to check if the HashMap is empty. But another answer seems to get the hint I needed. If I delete the value the entry will be null? Can i do a check if every entry is null easily or do i have to iterate over every entry again?
You do not delete a value from a Map you delete a mapping. this code does not delete any thing:
myMap.remove(entry);
because you pass the entry object, you need to pass the key of the mapping on order to delete it, see Map.html#remove docs.
thus
myMap.remove(entry.getkey());
However with the current approach you will run in ConcurrentModificationException. If it didnt till now it's just because your code didn't delete anything, because you pass the entry object
If you delete the mapping from the map, that mapping will no longer exist in the map. Whether the bucket is null or not is implementation detail, but when you query a mapping that was deleted using the given key you'll get null as return value. If you add another mapping with the same key you will get taht mapping again.
You can check if a map is empty using Map#isEmpty, thus you dont need to check if every entry is null or iterate over the whole map to do so.
You can check if a map contain a mapping for a key using Map.#containsKey
You can check if a map caintains at least one mapping for a value using Map#containsValue
the correct way to delete etriey from a map while iteration it to use an iterator
Iterator<Entry<Integer, String>> iterator = myMap.entrySet().iterator();
while(iterator.hasNext()) {
Entry<Integer, String> entry = iterator.next();
if (entry.getValue().contains("foo")) {
iterator.remove();
}
}
Since you have Map<Integer, String> I assume that the position you mean is the integer key, where you do something like myMap.put(1, "."), myMap.put(2, ".."), myMap.put(3, "...") and so on. In that case if you remove the mapping for the key 1 for example, the postion, i.e the mapping {1 : "."} will no longer exist in the map.

OK I got a codeable example that's pretty easy.
public class TestingThingsOut {
public static void main(String [] args) {
HashMap<Integer, String> myMap = new HashMap<Integer, String>();
myMap.put(123, "hello");
myMap.put(234, "Bye");
myMap.put(789, "asdf");
System.out.println(myMap); // it says:
{789=asdf, 234=Bye, 123=hello}
System.out.println(myMap.size()); // it says: "3"
for (Entry<Integer, String> entry : myMap.entrySet()) {
if (entry.getValue().contains("hello")) {
myMap.remove(entry);
}
}
System.out.println(myMap); // it says:
{789=asdf, 234=Bye, 123=hello}
System.out.println(myMap.size()); // it says: "3" again
}
}

Related

Java Iterate through a HashMap<?, List<?>> and for each Key count how many Values the Key has

I'm having problems on how to tackle this since I know a map has no specific order. I would think that you would iterate over the map's Keys and then check the value count by getting the size of the LinkedList since the Values to the Key are held in a LinkedList I can just call a size or length call for the LinkedList, but my main question is how to get inside the HashMap with an iterator first to do this?
An iterator over all the entries of a map can be done as follows in Java:
for (Map.Entry<Key, Value> entry : map.entrySet()) {
Key k = entry.getKey();
Value v = entry.getValue();
// do something with k,v
}
However, a map can only contain at most one value associated with a key. So, if using a map of lists to associate multiple values, the list would be accessed simply through get.
I suppose you have something like this :
Map<Integer,List<Integer>> map = new HashMap<>();
You can just iterate very simply through all the values you have.
for (List<Integer> values : map.values()){
System.out.println(values.size());
}

How to put multiple values in Map from a list

I have a list gotitems.
ArrayList<String> gotitems = new ArrayList<String>();
i need to put that list in a hashmap called map.
Map<String,String> map = new HashMap<String,String>();
i had tried this :
for(String s:gotitems){
map.put("a",s);
}
gotitems contains :
First
Second
Third
But the output of :
System.out.println(map.values());
gives :
Third
Third
Third
i had even tried this :
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
but this is also not working.
What am i doing wrong here ?
As per Map put(K,V) method docs
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value.
You are ovverriding the key each time here .
for(String s:gotitems){
map.put("a",s);
}
change the key each time and try like
for(String s:gotitems){
map.put(s,s);
}
This is because you are putting all the items in the map against the same key "a"
map.put("a");
You need to store each element against a unique key so add something like this:
int count = 0;
for(String s:gotitems){
map.put("a" + count,s);
count++;
}
You are trying to put three Strings in the map under the same key "a". Try to use unique keys for your values.
You're putting all your items in the Map with the same key: "a".
You should have a unique String key for each value.
For instance:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Map<String, String> map = new LinkedHashMap<String, String>();
for (String s: list) {
map.put(s, s);
}
System.out.println(map);
Output:
{one=one, two=two, three=three}
Note the LinkedHashMap here: it maintains the order in which you put your key/value pairs.
Edit Of course if your List does not have unique values, moving its values as keys to a Map will overwrite some of the Map's values. In that case you want to ensure your List has unique keys first, or maybe use a Map<Integer, String> with the index of the List's value as key to the Map, and the actual List value as value to the Map.
When you write
for(String s:gotitems){
map.put("a",s);
}
you will trash any existing entry in the map held against the key "a". So after your iteration, your map will contain just one entry corresponding to the last iterated value in gotitems.
To use a map effectively you need to consider what your keys will be. Then use map.put(myKeyForThisItem, s) instead. If you don't have an effective scheme for the keys then using a map is pointless as one tends to use the keys to extract the corresponding values.
As for your second approach, it would be helpful if you could define "it is not working" a little clearer: perhaps iterate through the map and print the keys and values.
Please note that in a map, a key can point to at most one value. In your case, you are doing the following mappings:
"a" -> "one"
then you overwrite it as
"a" -> "two"
then you overwrite it as
"a" -> "three"
remember: a key can point to at most one value. However, a value can be pointed at by multiple keys.
This is wrong:
for(String s:gotitems){
map.put("a",s);
}
Since you are using "a" common key for all values, last inserted key-value pair would be preserved, all previous ones would be overridden.
This is also not correct:
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
you are putting n*n times into map, though you want only n (gotitems.size()) items into map.
First decide on key which you want to use in map, copying List into Map one approach could be use index as key:
for(int j=0;j<gotitems.size();j++){
map.put("KEY-"+j,gotitems.get(j));
}
Output should be:
KEY-0 First
KEY-1 Second
KEY-2 Third
I have reproduce your codes. The problem is that you are assigning the same key to different value. This should work.
import java.util.*;
public class testCollection{
public static void main(String[] args){
ArrayList<String> gotitems = new ArrayList<String>();
gotitems.add("First");
gotitems.add("Second");
gotitems.add("Third");
Map<String,String> map = new HashMap<String,String>();
String x = "a";
int i = 1;
for(String s:gotitems){
map.put(x+i,s);
i++;
}
System.out.println(map);
}
}

Retrieving the previous key-map value before it was overwritten in a HashMap

I have created a HashMap as per my code...
HashMap map=new HashMap();//HashMap key random order.
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
System.out.println("There are "+map.size()+" elements in the map.");
System.out.println("Content of Map are...");
Set s=map.entrySet();
Iterator itr=s.iterator();
while(itr.hasNext()){
Map.Entry m=(Map.Entry)itr.next();
System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
}
When I execute this code, the value for key=Saral is Android. Is there any way that I can get the previous value for this key, which was J2EE?
No, you can't have that with a standard HashMap. The easiest solution would be to store a List as value in the map though, and then you can add multiple items to the list (Btw you should use generic collections too). To simplify, you could use a helper method like this:
void addToMap(Map<String, List<String>> map, String key, String value) {
List<String> list = map.get(key);
if (list == null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(value);
}
Map<String, List<String>> map = new HashMap<String, List<String>>();
addToMap(map, "Amit", "Java");
addToMap(map, "Saral", "J2EE");
addToMap(map, "Saral", "Andriod");//same key but different value
addToMap(map, "Nitin", "PHP");
addToMap(map, "hj", "Spring1");
...
The helper method here is just an illustration - a full, robust implementation may need to include e.g. checks for duplicate values, depending on whether you allow them. If not, you may prefer using a Set instead of List.
Update
To print out the contents of this map, you need to use an embedded loop to iterate through the list of values for each map entry (btw you can use a foreach loop instead of an iterator):
for (Map.Entry<String, List<String>> m : map.entrySet())
{
for (String v : m.getValue())
{
System.out.println(m.getKey()+"\t"+v+"\t"+ m.hashCode());
}
}
A Map can contain at most one entry per key, so when you call map.put("Saral","Andriod"), the old "J2EE" value is removed. To support multiple values per key, you would need to maintain a Map<String, List<String>> or else a multi-map implementation such as Guava's Multimap.
As a side note I would recommend you start using generics, for example Map<String, String>, Iterator<String>, etc. for type safety at compile time.
The old value is overwritten (replaced). There will be only one mapping (entry) for one unique key. There fore it does not exist anymore so you can not retrieve it.
You cannot do this with standard implementations of Map that Java provides. However there are implementations of MultiMap (that's basically what you're after).
One example is this one from Google:
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html
Note that you won't be able to just get this one interface, you'll need a few classes along with it.
As other have said, this won't work with a standard Map. However, Google's Guava provides a MultiMap interface, which you can use to store multiple values with a single key.
Example of use:
Multimap<String,String> multiMap = ArrayListMultimap.create();
multiMap.put("color", "red");
multiMap.put("color", "blue");
System.out.println(multiMap.get("color")); //returns a ["red', "blue"] list

Get the last value in map

How can i get the last and first key/value of a Map?
For example:
Map<String,Integer> ret = new HashMap<String,Integer>();
And this is ret's value:
{33=1, 12=2, 21=2, 93=2, 48=9, 68=10}
You cannot do it with HashMap because keys are not ordered. Consider using LinkedHashMap
You can get last element using this method:
public <K,V> Map.Entry<K,V> getLast(LinkedHashMap<K,V> map) {
Iterator<Map.Entry<K,V>> iterator = map.entrySet().iterator();
Map.Entry<K, V> result = null;
while (iterator.hasNext()) {
result = iterator.next();
}
return result;
}
A HashMap is an unordered map, so it doesn't have any concept of 'first' or 'last.
If you want a map that retains things in insertion order, you can use a LinkedHashMap, and then iterate its entrySet() method to pick the first and last values.
You could also use the SortedMap interface (TreeMap impl.) which orders inserted entries by the natural ordering of keys (or a provided Comparator).
It isn't possible (or more like doesn't make sense) to differentiate between "first" and "last" when it comes to HashMap. If you want to preserve insertion order, you might want to use LinkedHashMap<K,V>. But then again, you should elaborate your question to let us know the exact use case demanding this.
since there is no defined order you will basically get a random element if you are unlucky.
else you could go the way HashMap -> getEntrySet -> toArray -> get(size-1)
Technically, you can get the first object from the map via:
Map.Entry<Integer,Integer> entry = map.entrySet().iterator().next();
And the last via:
Iterator<Map.Entry<Integer,Integer>> iter = map.entrySet().iterator();
Map.Entry<Integer,Integer> entry = null;
while(iter.hasNext()) {
entry = iter.next();
}
// now you have the "last" item in the map stored in 'entry'
But, as has been stated in other answers, this doesn't mean anything with a HashMap. Substitute it with a LinkedHashMap, however, and you can get the first and last inserted pairs out using the above code.
Unless you use a http://docs.oracle.com/javase/6/docs/api/java/util/SortedMap.html, in which case you could get the first and last key..

Using the keySet() method in HashMap

I have a method that goes through the possible states in a board and stores them in a HashMap
void up(String str){
int a = str.indexOf("0");
if(a>2){
String s = str.substring(0,a-3)+"0"+str.substring(a-2,a)+str.charAt(a-3)+str.substring(a+1);
add(s,map.get(str)+1);
if(s.equals("123456780")) {
System.out.println("The solution is on the level "+map.get(s)+" of the tree");
//If I get here, I need to know the keys on the map
// How can I store them and Iterate through them using
// map.keySet()?
}
}
}
I'm interested in the group of keys. What should I do to print them all?
HashSet t = map.keySet() is being rejected by the compiler as well as
LinkedHashSet t = map.keySet()
Use:
Set<MyGenericType> keySet = map.keySet();
Always try to specify the Interface type for collections returned by these methods. This way regardless of the actual implementation class of the Set returned by these methods (in your case map.keySet()) you would be ok. This way if the next release the jdk guys use a different implementation for the returned Set your code will still work.
map.keySet() returns a View on the Keys of the map. Making changes to this view results in changing the underlying map though those changes are limited. See the javadoc for Map:
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Map.html#keySet%28%29
Map<String, String> someStrings = new HashMap<String, String>();
for(Map.Entry<String, String> entry : someStrings.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
This is how I like to iterate through Maps. If you specifically want just the keySet(), that answer is elsewhere on this page.
for ( String key : map.keySet() ) {
System.out.println( key );
}
Set t = map.ketSet()
The API does not specify what type of Set is returned.
You should try to declare variables as the interface rather than a particular implementation.
Just
Set t = map.keySet();
Unless you're using an older JDK, I think its a little cleaner to use generics when using the Collections classes.
So thats
Set<MyType> s = map.keySet();
And then if you just iterate through them, then you can use any kind of loop you'd like. But if you're going to be modifying the map based on this keySet, you you have to use the keySet's iterator.
All that's guaranteed from keySet() is something that implements the interface Set. And that could possibly be some undocumented class like SecretHashSetKeys$foo, so just program to the interface Set.
I ran into this trying to get a view on a TreeSet, the return type ended up being TreeSet$3 on close examination.
Map<String, Object> map = new HashMap<>();
map.put("name","jaemin");
map.put("gender", "male");
map.put("age", 30);
Set<String> set = map.keySet();
System.out.println("this is map : " + map);
System.out.println("this is set : " + set);
It puts the key values in the map into the set.
From Javadocs HashMap has several methods that can be used to manipulate and extract data from a hasmap.
public Set<K> keySet()
Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.
Specified by:
keySet in interface Map
Overrides:
keySet in class AbstractMap
Returns:
a set view of the keys contained in this map
so if you have a map myMap of any datatype , such that the map defined as map<T> , if you iterate it as follows:
for (T key : myMap.keySet() ) {
System.out.println(key); // which represent the value of datatype T
}
e.g if the map was defined as Map<Integer,Boolean>
Then for the above example we will have:
for (Integer key : myMap.keySet()){
System.out.println(key) // the key printed out will be of type Integer
}

Categories

Resources