remove key from hash table - java

I want to remove key from hash Table without using the remove function. so give me some idea.

You can emulate removed keys by supplementing a Map<K,V> map with a Set<K> removedKeys.
To remove a key, just removedKeys.add(key);.
Whenever a K key is queried, you see if removedKeys.contains(key). If it does, then key has effectively been "removed" from map.
Note that this is a very peculiar way of doing things, and keeping the two structures in sync may cause later headaches. It's more acceptable if removedKeys is localized and short-lived, e.g. when you're iterating over the entries of a Map using for-each and want to remove some keys later, while avoiding ConcurrentModificationException.
So you may have something like this:
static void removeEvenKeys(Map<Integer,String> map) {
Set<Integer> removedKeys = new HashSet<Integer>();
for (Map.Entry<Integer,String> entry : map.entrySet()) {
if (entry.getKey() %2 == 0) {
removedKeys.add(entry.getKey());
}
}
map.keySet().removeAll(removedKeys);
}
And then elsewhere:
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
map.put(4, "Four");
removeEvenKeys(map);
System.out.println(map);
// "{1=One, 3=Three}"
See also
Effective Java 2nd Edition, Item 52: Refer to objects by their interfaces
Related questions
Java hashmap vs hashtable
Java: Efficient Equivalent to Removing while Iterating a Collection

You can call remove() on an Iterator instead of on the Hashtable itself:
Hashtable<String, String> map = new Hashtable<String, String>();
map.put("one", "een");
map.put("two", "twee");
map.put("three", "drie");
for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<String, String> entry = i.next();
if ("two".equals(entry.getKey())) {
// Removes entry from Hashtable; note, this is not the Hashtable.remove() method
// but the Iterator.remove() method
i.remove();
}
}
System.out.println(map);
(NOTE: You should use HashMap instead of the legacy collection class Hashtable).

Related

ConcurrentModificationException when using iterator to remove entry

I have a simple piece of code that loops through a map, checks a condition for each entry, and executes a method on the entry if that condition is true. After that the entry is removed from the map.
To delete an entry from the map I use an Iterator to avoid ConcurrentModificationException's.
Except my code does throw an exception, at the it.remove() line:
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.remove(Unknown Source) ~[?:1.8.0_161]
at package.Class.method(Class.java:34) ~[Class.class:?]
After a long search I can't find a way to fix this, all answers suggest using the Iterator.remove() method, but I'm already using it. The documentation for Map.entrySet() clearly specifies that it is possible to remove elements from the set using the Iterator.remove() method.
Any help would be greatly appreciated.
My code:
Iterator<Entry<K, V>> it = map.entrySet().iterator();
while (it.hasNext()) {
Entry<K, V> en = it.next();
if (en.getValue().shouldRun()) {
EventQueue.invokeLater(()->updateSomeGui(en.getKey())); //the map is in no way modified in this method
en.getValue().run();
it.remove(); //line 34
}
}
If you cannot change HashMap to ConcurrentHashMap you can use another approach to your code.
You can create a list of entries containing the entries that you want to delete and then iterate over them and remove them from the original map.
e.g.
HashMap<String, String> map = new HashMap<>();
map.put("1", "a1");
map.put("2", "a2");
map.put("3", "a3");
map.put("4", "a4");
map.put("5", "a5");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
List<Map.Entry<String, String>> entries = new ArrayList<>();
while (iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
if (next.getKey().equals("2")) {
/* instead of remove
iterator.remove();
*/
entries.add(next);
}
}
for (Map.Entry<String, String> entry: entries) {
map.remove(entry.getKey());
}
Please use ConcurrentHashMap in place of HashMap as you are acting on the object in multiple threads. HashMap class isn't thread safe and also doesn't allow such operation. Please refer below link for more information related to this.
https://www.google.co.in/amp/s/www.geeksforgeeks.org/difference-hashmap-concurrenthashmap/amp/
Let me know for more information.
For such purposes you should use the collection views a map exposes:
keySet() lets you iterate over keys. That won't help you, as keys are
usually immutable.
values() is what you need if you just want to access the map values.
If they are mutable objects, you can change directly, no need to put
them back into the map.
entrySet() the most powerful version, lets you change an entry's value
directly.
Example: convert the values of all keys that contain an upperscore to uppercase
for(Map.Entry<String, String> entry:map.entrySet()){
if(entry.getKey().contains("_"))
entry.setValue(entry.getValue().toUpperCase());
}
Actually, if you just want to edit the value objects, do it using the values collection. I assume your map is of type <String, Object>:
for(Object o: map.values()){
if(o instanceof MyBean){
((Mybean)o).doStuff();
}
}

How to iterate hashmap in reverse order in Java

I am trying this for some hour but not finding any best approach to achieve iteration of hashmap in reverse order, this is the hashmap I have.
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
for(Integer key : map.keySet()) {
List<String> value = map.get(key);
List<Map<String,?>> security = new LinkedList<Map<String,?>>();
for(int ixy = 0; ixy < value.size()-1; ixy++){
security.add(createItem(value.get(ixy), value.get(ixy+1)));
}
adapter.addSection(Integer.toString(key), new SimpleAdapter(getApplicationContext(), security, R.layout.list_complex, new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));
}
I have seen example of TreeMap as well,
Map<Integer, List<String>> sortedMap = new TreeMap<Integer, List<String>>(map);
But treemap also gives in ascending order, what I want is in descending order.
best approach to acheive iteration of hashmap in reverse order
HashMap does not define any particular ordering of its element. Therefore the "reverse" order isn't defined either.
For a TreeMap, you can use descendingMap().
Hashmap does not have specific order. But you can use TreeMap.
Perhaps this simple example can help you :
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "abc1");
map.put(2, "abc2");
map.put(3, "abc3");
ArrayList<Integer> keys = new ArrayList<Integer>(map.keySet());
for(int i=keys.size()-1; i>=0;i--){
System.out.println(map.get(keys.get(i)));
}
A HashMap doesn't maintain eny order between keys.
A TreeMap orders its keys by their natural order, or by the order imposed by a comparator that you pass when constructing the map. So if you want to have Integer keys ordered in reverse order, construct the TreeMap this way:
Map<Integer, List<String>> sortedMap =
new TreeMap<Integer, List<String>>(Collections.reverseOrder());
Map<Integer, List<String>> sortedMap = new TreeMap<Integer, List<String>>(Collections.reverseOrder());
Collections.reverseOrder() keeps the map sorted in descending order.
You can use TreeMap#descendingKeySet method.
Map<Integer, List<String>> map = new TreeMap<Integer, List<String>>();
for(Integer key : map.descendingKeySet()) {
List<String> value = map.get(key);
List<Map<String,?>> security = new LinkedList<Map<String,?>>();
for(int ixy = 0; ixy < value.size()-1; ixy++){
security.add(createItem(value.get(ixy), value.get(ixy+1)));
}
adapter.addSection(Integer.toString(key), new SimpleAdapter(getApplicationContext(), security, R.layout.list_complex, new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));
}
Reference:
https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html#descendingKeySet--
You can't iterate over a HashMap in reverse because of this:
This class makes no guarantees as to the order of the map; in
particular, it does not guarantee that the order will remain constant
over time.
What you should use is a LinkedHashMap:
This implementation differs from HashMap in that it maintains a
doubly-linked list running through all of its entries. This linked
list defines the iteration ordering, which is normally the order in
which keys were inserted into the map (insertion-order). Note that
insertion order is not affected if a key is re-inserted into the map.
(A key k is reinserted into a map m if m.put(k, v) is invoked when
m.containsKey(k) would return true immediately prior to the
invocation.)
The hashmap is not an ordered collection. Use TreeMap instead, which has descendingKeySet for reverse iteration. See the javadocs. LinkedHashMap is also a good choice.
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "abc1");
map.put(2, "abc2");
map.put(3, "abc3");
NavigableMap<Integer, String> nmap = map.descendingMap();
for (NavigableMap.Entry<Integer, String> entry : nmap.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
An implementation of NPE idea.
Perhaps you need a NavigableMap, like a TreeMap.
But treemap also gives in asecding order, what i want is in descending order.
Implement a Comparator that will compare it reverse than natural order and then just iterate normally you will have reverse iteration
Use insted:
new TreeMap<>(Collections.reverseOrder())
and you will get what you want.
I've found that the Iterators obtained from Java Hashtable via:
Hashtable.values().iterator() and Hashtable.keys().asIterator()
are both in reverse order by default. One oddity, The values().iterator has a first final value of "0" which I didn't add when populating it.

Sorting HashMaps by value

When I need to sort a HashMap by value, the advice seems to be to create the HashMap and then put the data into a TreeMap which is sorted by value.
For example: Sort a Map<Key, Value> by values (Java)
My question: why is it necessary to do this? Why not create a TreeMap(which is sorted by keys) and then sort it in place by value?
If you know your values to be unique, you can use Guava's BiMap (bidirectional map) to store the data. Create a HashBiMap as you would your HashMap, then create a new TreeMap from its inverse:
new TreeMap<>(biMap.inverse());
That map will then be sorted by the values. Remember that what you're thinking of as "keys" and "values" will be swapped.
If your values are not unique, you can create a multimap of the inverse. A multimap is essentially a mapping from each key to one or more values. It's usually implemented by making a map from a key to a list. You don't have to do that though, because Google did it for you. Just create a multimap from your existing map, and ask Guava to invert it for you into a TreeMultimap, which, as you can guess, is a TreeMap that can hold multiple values per key.
Multimaps.invertFrom(Multimaps.forMap(myMap), new TreeMultimap<V, K>());
Multimap documentation is provided.
Because you can't reorder the entries of a TreeMap manually. TreeMap entries are always sorted on the keys.
I'm going to throw out Map that could be iterated in the order of values as another answer to "How to do it," though...specifically, a solution which doesn't return a map that chokes (by throwing exceptions) on queries to keys not in your original map.
I have this very small code which is working fine:
public class SortMapByValues {
public static void main(String[] args) {
Map<Integer, String> myMap = new LinkedHashMap<Integer, String>();
myMap.put(100, "hundread");
myMap.put(500, "fivehundread");
myMap.put(250, "twofifty");
myMap.put(300, "threehundread");
myMap.put(350, "threefifty");
myMap.put(400, "fourhundread");
myMap = sortMapByValues(myMap);
for (Map.Entry<Integer, String> entry : myMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
public static Map<Integer, String> sortMapByValues(
Map<Integer, String> firstMap) {
Map<String, Integer> SecondyMap = new TreeMap<String, Integer>();
for (Map.Entry<Integer, String> entry : firstMap.entrySet()) {
SecondyMap.put(entry.getValue(), entry.getKey());
}
firstMap.clear();
for (Map.Entry<String, Integer> entry : SecondyMap.entrySet()) {
firstMap.put(entry.getValue(), entry.getKey());
}
return firstMap;
}
}
Output:
500 fivehundread
400 fourhundread
100 hundread
350 threefifty
300 threehundread
250 twofifty
I wrote the following one-liner using Java 8 Stream API to sort any given map by value:
List<Map.Entry<String, String>> sortedEntries = map.entrySet().stream()
.sorted((o1, o2) -> o1.getValue().compareTo(o2.getValue())).collect(Collectors.toList());

sorting treemap based on key, where key is variable

I want to sort the tree map based on the key where key is a variable,so sorting should be based on variable value, How can we achieve this? I want use in built sort method rathar implementing it through code, any reply with example is of great help.
TreeMap (which implements SortedMap) stores automatically the keys in the correct order:
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "one");
map.put(3, "three");
map.put(2, "two");
// prints one two three
for(Integer key : map.keySet()) {
System.out.println(map.get(key));
}
As Key-Type (in that case Integer) you can use any class which implements Comparable (or you can provide a Comparator when creating the TreeMap)
Edit: Okay, here is a suggestion how to re-map your map.
Map<Integer, String> oldMap; // get oldMap from somewhere
// Prepare remapping
Map<Integer, String> newMap = new TreeMap<Integer, String>();
Map<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
// Store a new key for each old key
keyMap.put(oldKey, newKey);
// fill the newMap
for(Integer oldKey : keyMap.keySet()) {
newMap.put(keyMap.get(oldKey), oldMap.get(oldKey));
}
oldMap = newMap; // if needed
A treemap is a Red-black tree, which is a balanced binary search tree. In other words, the tree is already sorted (or rather, arranged as per the binary search tree rules) with its height balanced so that tree operations have a O(lg n) complexity. However, I think what you want is to print all the keys in sorted order. This is as simple as implementing an inorder traversal on the treemap, or you could use the keySet() method to get a Set and iterate over the values.
e.g. of inorder traversal
void inorderTraversal( Node root ){
if( root == null ) return;
inorderTraversal( root.getLeft() );
root.printValue();
inorderTraversal( root.getRight() );
}
EDIT:
Okay, I'm pretty sure this is what you want. You want to sort by values:
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("one", 8);
map.put("two", 10);
map.put("three", 9);
map.put("hundred", 1);
System.out.println(map.values());
Output:
[1, 8, 9, 10]
So this works even for sorting string values:
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(8, "one");
map.put(10, "two");
map.put(9, "three");
map.put(1, "hundred");
System.out.println(map.values());
Output:
[hundred, one, three, two]
Also, sachin take note that having "variable keys" and variable values are completely different things.
TreeMap implements the SortedMap interface and is sorted by its key without you having to do anything:
The map is sorted according to the natural ordering of its keys, or by
a Comparator provided at map creation time, depending on which
constructor is used.

Map: How to get all keys associated with a value?

Given a Map, how do I look up all keys associated with a particular value?
For example:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(1, 5);
map.put(2, 2);
map.put(3, 5);
Collection<Integer> keys = map.values(5); // should return {1, 3}
I'm looking for something similar to Google Collections' BiMap where values are not unique.
With plain java.util.Map implementations, I am afraid you must iterate through the map entries and test each value:
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue().equals(desiredValue) {
keys.add(entry.getKey());
}
}
If you want better performance, you may want to build up a parallel mapping from values to lists of keys. I don't know of any existing collection doing this, but it should not be difficult to implement.
From Java 8 onwards you can use map.forEach:
map.forEach((k,val) -> {
if (val.equals(desiredValue) {
keys.add(k);
}
});

Categories

Resources