Remove an Element From HashTable? - java

I want to remove elements from HashTable,
I use hashTable.remove() for this but not getting
Hashtable<Integer,String> players = new Hashtable<Integer,String>();
players.put(1, "Sachin Tendulkar");
players.put(2, "Rahul Dravid");
players.put(3, "Virat Kohli");
players.put(4, "Rohit Sharma");
Enumeration<String> enumration = players.elements();
while(enumration.hasMoreElements()){
String elmnt = enumration.nextElement();
System.out.println(elmnt);
if(elmnt.startsWith("R")){
players.remove(elmnt);
System.out.println(elmnt+"::Contains R");
}
}
System.out.println(players);
The output that i get is:
Rohit Sharma
Rohit Sharma::Contains R
Virat Kohli
Rahul Dravid
Rahul Dravid::Contains R
Sachin Tendulkar
{4=Rohit Sharma, 3=Virat Kohli, 2=Rahul Dravid, 1=Sachin Tendulkar}

That's because you're trying to remove the value, but the remove() method expects a key.
When you're calling player.elements() you get an enumeration of the values, not the keys. The remove() method works on a key, not a value.
From HashTable remove() documentation
public V remove(Object key):
Removes the key (and its corresponding value) from this hashtable. This method does nothing if the key is not in the hashtable.
Also, from the same documentation, here's a brief explanation on why it is not a good idea to use Enumeration to remove elements:
Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. The Enumerations returned by Hashtable's keys and elements methods are not fail-fast.
What I would suggest you to do is to iterate over the entries, not the values.
for (Entry<Integer, String> entry: players.entrySet()){
String value = entry.getValue();
System.out.println(value);
if(value.startsWith("R")){
players.remove(entry.getKey());
System.out.println(value+"::Contains R");
}
}
This way you have both the key and the value in each iteration. You can examine the value (which is the player's name) and then use the key in order to manipulate your table.

for(Iterator<Map.Entry<Integer, String>> iter = players.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<Integer, String> e = iter.next();
if(e.getValue().startsWith("R")) {
iter.remove();
}
}

You need to pass key as argument in hashTable.remove() to remove from HashTable.
Reference : Remove from HashTable
Best way to remove an entry from a hash table.
This may be helpful to you, have a look at it.

Don't remove from enumerations.
Javadocs:
"Thus, in the face of concurrent modification, the iterator fails
quickly and cleanly, rather than risking arbitrary, non-deterministic
behavior at an undetermined time in the future. The Enumerations
returned by Hashtable's keys and elements methods are not fail-fast."
You should using iterator:
import java.util.Hashtable;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Hashtable<Integer,String> players = new Hashtable<Integer,String>();
players.put(1, "Sachin Tendulkar");
players.put(2, "Rahul Dravid");
players.put(3, "Virat Kohli");
players.put(4, "Rohit Sharma");
Iterator<Integer> iterators = players.keySet().iterator();
while(iterators.hasNext()) {
int key = iterators.next();
if(players.get(key).startsWith("R")) {
iterators.remove();
}
}
System.out.println(players);
}
}

please add key to remove() method rather than value.
Hashtable<String, Integer> h = new Hashtable<String, Integer>();
h.put("n1", 30);
h.put("n2", 30);
h.remove("n1"); //here we are giving "n1" which is key of the hashTable

players.remove(elmnt); method try to remove the entry of elmt key. But you passed value of Hashtable instead of key.

Use players.keySet() to get the keys in place of players.elements().

Here is your syntax for coding for removing an element from hash tables:-
public virtual void Remove(
Object key
)
A mutual hash table can be manipulated with hash ref and hash remove. Concurrently by multiple threads and the operations are protected by a table-specific semaphore as needed.
Whereas, Deleting a record must not hinder later searches. In other words, the search process must still pass through the newly emptied slot to reach records whose probe sequence passed through this slot.

Related

Iterator for ConcurrentHashMap giving strange result

ConcurrentHashMap is thread safe. So if am adding any values to map at the time of iterating, it should not consider them. Below is my code:
public class Test {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
map.put("ONE", 1);
map.put("TWO", 2);
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
System.out.println(key + " : " + map.get(key));
map.put("9", 10); // This should not be reflected in the Iterator
map.put("5", 10); // This should not be reflected in the Iterator
}
}
}
Output:
TWO : 2
ONE : 1
9 : 10
My question is why iterator considering map.put("9", 10);
ConcurrentHashMap is thread safe. So if am adding any values to map at the time of iterating, it should not consider them.
That is not correct. This is what the javadoc says:
"Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration."
Note the "or since"!
And it also says that the iterators are "weakly consistent" which means that:
"they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction."
In short, you are expecting properties of the iterators that the javadocs plainly do not say that they have.
ConcurrentHashMap is thread safe, but this is a different scenario.
With a List you can use ListIterator with ListIterator.Add which is designed for that.
With HashMap I see two solutions:
Convert to List and then back to HashMap
Use an additional HashMap
for new elements, after the loop ends, use another loop to add all new
elements (not quite elegant, but works!).
With Java 8 you may consider using lambda-expressions to simplify the code.

Java HashMap add new entry while iterating

In a HashMap
map = new HashMap<String,String>();
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
it.remove(); //safely remove a entry
entry.setValue("new value"); //safely update current value
//how to put new entry set inside this map
//map.put(s1,s2); it throws a concurrent access exception
}
When i trying to add a new entry to map it throws ConcurrentModificationException. For remove and update iterator has safely removing methods. How to add new entry while iterating?
You need to consider what it means to put a value to a Map whilst iterating. HashMap defines no order over which its entries will be iterated over. So when you put a new entry, should the entry be returned by the iterator later or not. Consistency of behaviour is important. However, whichever way you decide you'll get inconsistent behaviour when you put a new value to a preexisting key. If the key has already been iterated over then the change won't appear and will appear if the key has yet to be produced by the iterator.
A simple way to overcome this problem is to create a temporary Map of the new key-value pairs and add the temporary Map to the main Map at the end of your iteration.
Map<String,String> values = ...
Map<String,String> temp = new HashMap<>();
for (Entry<String,String> entry : values.entrySet()) {
if ("some value".equals(entry.getValue()) {
temp.put(entry.getValue(), "another value");
}
}
values.putAll(temp);
You need to use ConcurrentHashMap to add elements while iterating the collection. HashMap uses fail-fast iterator, which throws ConcurrentModificationException when the collection is updated while iterating. Whereas ConcurrentHashMap uses fail-safe iterator, which basically works on the clone of the underlying collection and hence allows modification while iterating.
How about:
map = new HashMap<String,String>();
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
entry.setValue("new value"); // update current value
}
I checked the HashMap implementation, it does not change its modification count when updating an entry like this. I also see no reason why this shouldn't be allowed. Nothing is removed, nothing is added and no keys are changed.
What I did was to create an array with the current elements and then iterate through the array:
Feature[] initialFeatures = featureMap.values().toArray(new Feature[featureMap.values().size()]);
for (Feature feature : initialFeatures)
{/* Code that can safely add to the featureMap */}

Using ConcurrentHashMap efficiently?

I have a Android Application whose core component is a HashMap<String,float[]>.
The System is having high concurrency. e.g
here are the following three situations I have which occur frequently and they are highly overlapping in nature
Iterate through all the keys in the hashmap and do some operation on
its value(read only operations).
Add new key,value pairs in the Hashmap.
Remove Certain keys from the Hashmap.
I do all these operations in different threads and thus am using a ConcurrentHashMap since some inconsistency in retrievals doesnt matter. e.g While iterating the map,if new entries are added then it doesnt matter to not read in those new values immediately as I ensure that next time they are read .
Also while removing the entries I am recreating the iterator everytime to avoid "ConcurrentModificationException"
Suppose , there is a following hashmap(i.e ConcurrentHashmap)
ConcurrentHashMap<String,float[]> test=new ConcurrentHashMap<String, float[]>(200);
Now for Retrieval I do the following
Iterator<String> reader=test.keySet().iterator();
while(reader.hasNext())
{
String s=reader.next();
float[] temp=test.get(s);
//do some operation with float[] temp here(read only operation)
}
and for removal I do the following
boolean temp = true;
while (temp) {
for (String key : test.keySet()) {
temp = false;
if (key.contains("abc")) {
test.remove(key);
temp = true;
break;
}
}
}
and when inserting in new values I simply do
test.put("temp value", new float[10]);
I am not sure if its a very efficient utilisation. Also it does matter not to read in removed values(however I need efficiency ,and since the iterator is again created during the function call,its guaranteed that in the next time I don't get the removed values)so that much inconsistency can be tolerated?
Could someone please tell me an efficient way to do it?
PS. I forgot to mention that why I am doing the removal operation in such a way.
I have now changes the condition on which its deleted from equal to contains(there might be multiple stings having the prefix "abc" followed by different suffixes. so I need to delete all those then.
Iterate through all the keys in the hashmap and do some operation on its value(read only operations).
Don't iterate over the key set to then retrieve the values too - iterate over the entry set directly:
for (Map.Entry<String, float[]> e : map.entrySet() {
String key = e.getKey();
float[] value = e.getValue();
//do something with them
}
This is more efficient in general (even for "normal" HashMaps), but it will also reduce contention in your case (half as many accesses to the map).
Add new key,value pairs in the Hashmap.
Yes it is simply: map.put(s, f);
Remove Certain keys from the Hashmap.
If you need to check that the key contains a given substring then you do need to iterate over the keys like you are doing, although I'm not sure why you have a while+for+break instead of a simple for.
Because of the way you are using the ConcurrentHashMap, you are precisely removing its Concurrent characteristics. Your attempts at (re-)synchronization will work very frequently, but not always.
Have you considered to leave the keys in the HashMap? I'm thinking of something like:
public static final float[] DELETED= new float[0] ;
/* delete */
test.put(key,DELETED);
/* insert */
test.put(key,value);
/* iterate */
for(Map.Entry<String,float[]> e: test.entrySet ) {
if( e.getValue() != DELETED ) {
operateOn(e);
}
}
If keys are too volatile (i.e. after a while you would have too many DELETED items), then you can create a cleanup Thread.
According to ConcurrentHashMap API its iterators never throw ConcurrentModificationException so you dont need to break after removal. But in any case the correct way to iterate and remove is this
for (Iterator<String> i = test.keySet().iterator(); i.hasNext();) {
String next = i.next();
if (next.equals("abc")) {
i.remove();
}
}
this way it will work even with fail-fast iterators without ConcurrentModificationException

How to get position of key/value in LinkedHashMap using its key

I have a LinkedHashMap (called info) that contains name/age (string/int) pairs. How can I get the position of the key/value if I input the key? For example, if my LinkedHashMap looked like this {bob=12, jeremy=42, carly=21} and I was to search jeremy, it should return 1 as its in position 1. I was hoping I can use something like info.getIndex("jeremy").
HashMap implementations in general are un-ordered for Iteration.
LinkedHashMap is predictablely ordered for Iteration ( insertion order ) but does not expose the List interface and a LinkedList ( which is what mirrors the key set insertion order ) does not track index position itself either, it is very in-efficient to find the index as well. The LinkedHashMap doesn't expose the reference to the internal LinkedList either.
The actual "Linked List" behavior is implementation specific. Some
may actually use an instance of LinkedList some many just have
Entry track a previous and next Entry and use that as its
implementation. Don't assume anything without looking at the source.
The KeySet that contains the keys does not guarantee order as well because of the hashing algorithms used for placement in the backing data structure of the inherited HashMap. So you can't use that.
The only way to do this, without writing your own implementation, is to walk the Iterator which uses the mirroring LinkedList and keep a count where you are, this will be very in-efficient with large data sets.
Solution
What it sounds like you want is original insertion order index positions, you would have to mirror the keys in the KeySet in something like an ArrayList, keep it in sync with updates to the HashMap and use it for finding position. Creating a sub-class of HashMap, say IndexedHashMap and adding this ArrayList internally and adding a .getKeyIndex(<K> key) that delegates to the internal ArrayList .indexOf() is probably the best way to go about this.
This is what LinkedHashMap does but with a LinkedList mirroring the KeySet instead of an ArrayList.
int pos = new ArrayList<String>(info.keySet()).indexOf("jeremy")
I saw a suggestion from one of the duplicates of this question at
How get value from LinkedHashMap based on index not on key?
and I liked the suggestion as described as pseudo code from #schippi in the comments. I thought some working Java code might be useful to others on this approach
import java.util.ArrayList;
import java.util.LinkedHashMap;
public class IndexedLinkedHashMap<K,V> extends LinkedHashMap<K,V> {
/**
*
*/
private static final long serialVersionUID = 1L;
ArrayList<K> al_Index = new ArrayList<K>();
#Override
public V put(K key,V val) {
if (!super.containsKey(key)) al_Index.add(key);
V returnValue = super.put(key,val);
return returnValue;
}
public V getValueAtIndex(int i){
return (V) super.get(al_Index.get(i));
}
public K getKeyAtIndex(int i) {
return (K) al_Index.get(i);
}
public int getIndexOf(K key) {
return al_Index.indexOf(key);
}
}
Considering that LinkedHashMap keep the order of insertion, you can use the keySet() and List.copyOf() (since Java 10) methods like this:
List<String> keys = List.copyOf( yourLinkedHashMap.keySet() );
System.out.println( keys.indexOf("jeremy") ); // prints '1'
LinkedHashMap has "predictable iteration order" (javadoc). Items don't know their location, though, so you'll have to iterate the collection to get it. If you're maintaining a large map you may want to use a different structure for storage.
Edit: clarified iteration
You can use com.google.common.collect.LinkedListMultimap from the Google Guava library. You don't need the multimap behaviour of this class what you want is that the keys() method guarantees they are returned in insertion order and can then be used to construct a List, you can use the indexOf() to find the required index position
I do extract the positons of the key into a concurent map like this:
Here for a Map, someListOfComplexObject() would be entrySet()
and getComplexStringKeyElem() would be getKey()
might come from
final int[] index = {0};
Stream<ComplexObject> t = someListOfComplexObject.stream();
ConcurrentMap<String, List<Integer>> m =
t.collect(Collectors.groupingBy(
e -> e.getComplexStringKeyElem(),
Collectors.mapping(
e -> index[0]++,
Collectors.toList()
),
ConcurrentSkipListMap::new));

Java - get index of key in HashMap?

In java if I am looping over the keySet() of a HashMap, how do I (inside the loop), get the numerical index of that key?
Basically, as I loop through the map, I want to be able to get 0,1,2...I figure this would be cleaner than declaring an int and incrementing with each iteration.
Thanks.
Use LinkedHashMap instead of HashMap
It will always return keys in same order (as insertion) when calling keySet()
For more detail, see Class LinkedHashMap
Not sure if this is any "cleaner", but:
List keys = new ArrayList(map.keySet());
for (int i = 0; i < keys.size(); i++) {
Object obj = keys.get(i);
// do stuff here
}
The HashMap has no defined ordering of keys.
If all you are trying to do is get the value out of the hashmap itself, you can do something like the following:
for (Object key : map.keySet()) {
Object value = map.get(key);
//TODO: this
}
Or, you can iterate over the entries of a map, if that is what you are interested in:
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
//TODO: other cool stuff
}
As a community, we might be able to give you better/more appropriate answers if we had some idea why you needed the indexes or what you thought the indexes could do for you.
You can't - a set is unordered, so there's no index provided. You'll have to declare an int, as you say. Just remember that the next time you call keySet() you won't necessarily get the results in the same order.
Simply put, hash-based collections aren't indexed so you have to do it manually.
Posting this as an equally viable alternative to #Binil Thomas's answer - tried to add it as a comment, but was not convinced of the readability of it all.
int index = 0;
for (Object key : map.keySet()) {
Object value = map.get(key);
++index;
}
Probably doesn't help the original question poster since this is the literal situation they were trying to avoid, but may aid others searching for an easy answer.
I was recently learning the concepts behind Hashmap and it was clear that there was no definite ordering of the keys.
To iterate you can use:
Hashmap<String,Integer> hs=new Hashmap();
for(Map.Entry<String, Integer> entry : hs.entrySet()){
String key=entry.getKey();
int val=entry.getValue();
//your code block
}
I don't know is this what you're looking for
List keys = new ArrayList(map.keySet());
int index = keys.indexOf(element);
You can directly get the keys in Set<K> keySet().
val teamMember = hashMapOf(
"Coach" to "manager",
"Player Coach" to "editor",
"Player" to "member",
"Supporter" to "readonly"
)
teamMember.keys.forEachIndexed { index, key ->
// Here is your key in string
}

Categories