Java LinkedHashMap replace key - java

Is there any way to replace a key using put() in a LinkedHashMap without losing the order that the key was originally inserted in?

You do not lose the order when putting a different value for the same key.
Example
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("foo", "bar");
map.put("blah", "baz");
System.out.println(map);
map.put("foo", "foo");
System.out.println(map);
Output
{foo=bar, blah=baz}
{foo=foo, blah=baz}
Edit
"Replacing" a key for a given value would imply removing the key value pair, then putting the new key with the stored value.
As such, there is no direct way to do this with a LinkedHashMap, probably not even by inheriting and changing the behavior of remove and put.

If you used the LinkedHashMap, I don't think there is built-in method to achieve your goal. You may want to pick another (or design your own) data-structure.
If you have to do it on a linkedhashmap, you can create a new LinkedHashMap, iterate the old one and put into the new one, when your target entry comes, create a new entry with different key, put the new entry into the map.

Related

How to add data and iterate Map of maps (Nested map) in Java?

Using Java8/Collections/
I want to add data in Map in collections as:
Map<String,Map<String,Double>> OuterMap=new LinkedHashMap<String,Map<String,Double>>();
Inner map:
Map<String,Double> InnerMap=new LinkedHashMap<String,Double>();
OuterMap.put("Str1",InnerMap);
OuterMap.put("Str2",InnerMap);
The issue is I want to check the keys of InnerMap and it may vary to each other in InnerMap.
When I compare the keys of InnerMap. The OuterMap overrides the previous elements of the map.
I want the output like:
Str1={"SNP1"=0.3,"SNP2"=0.56,"SNP3"="0.76"} , Str2={"SNP1"="0.16","SNP2"=0.56,"SNP3"=0.78,"SNP4"=.56}
You should be creating new map instances when storing the values.
The simplest way to create a copy of the map is to use appropriate copy constructor:
Map<String,Double> innerMap=new LinkedHashMap<>();
outerMap.put("Str1", innerMap);
outerMap.put("Str2", new LinkedHashMap<>(innerMap));
Please also make sure you adhere to Java naming conventions: camelCase for variables/fields/methods, UpperCamelCase for classes/interfaces/enums.

Java Map get key from value

below is my code...
Map<Integer, String> MyType = sessionInfo.getType();
//{2=somename}
I am trying to get key from value...without running any loops....is it possible?
MyType.get("somename") // should output 2`
It's not easy to get key from value in Hashtable or HashMap, as compared to getting value from key, because Hash Map or Hashtable doesn't enforce one to one mapping between key and value inside Map in Java. infact Map allows same value to be mapped against multiple keys inside HashMap, Hashtable or any other Map implementation.
String key= null;
String value="somename";
for(Map.Entry entry: MyType.entrySet()){
if(value.equals(entry.getValue())){
key = entry.getKey();
break; //breaking because its one to one map
}
}
I would encourage running a loop for simplicity. It most likely will not slow down your program a noticeable amount.
However, if you must not run a loop, Google's Guava library has a BiDirectional Map Collection called BiMap that can be (found here). The map works both ways and is guaranteed to be synchronized at all times. I also am assuming that you have unique values in your map. If you do not, duplicate values will not have a specific key to link to.
BiMap<String, Integer> biMapInversed = biMap.inverse(); // how to get inverted map
Again, I wouldn't encourage this unless absolutely necessary. Looping through will work perfectly fine in most cases.
Taken from this SO answer
If you choose to use the Commons Collections library instead of
the standard Java Collections API, you can achieve this with ease.
The BidiMap interface in the Collections library is a
bi-directional map, allowing you to map a key to a value (like normal
maps), and also to map a value to a key, thus allowing you to perform
lookups in both directions. Obtaining a key for a value is supported
by the getKey() method.
There is a caveat though, bidi maps cannot have multiple values mapped
to keys, and hence unless your data set has 1:1 mappings between keys
and values, you cannot use bidimaps.
This is not possible. You need to consider the value may be duplicated in map.
Ex, How do you deal with {2=somename} and {5=somename}
You still need to use a for loop to check value and get key and decide to break or go on when value is matched.
If you're sure that your values are unique you can iterate over the entries of your old map .
Map<String, Character> myNewHashMap = new HashMap<>();
for(Map.Entry<Character, String> entry : myHashMap.entrySet()){
myNewHashMap.put(entry.getValue(), entry.getKey());
}
Alternatively, you can use a Bi-Directional map like Guava provides and use the inverse() method :
BiMap<Character, String> myBiMap = HashBiMap.create();
myBiMap.put('a', "test one");
myBiMap.put('b', "test two");
BiMap<String, Character> myBiMapInversed = myBiMap.inverse();

Duplicates in LinkedHashMap

In my code I am using a set of interleaved LinkedHashMaps inside each other as below. The code is fine and gives me the result I want except it automatically removes the duplicates. I couldnt find out how I can use TreeMap or Set in order to keep the duplicates.
LinkedHashMap<String, LinkedHashMap<Integer, LinkedHashMap<String, Vector<String>>>>
dataAll =new LinkedHashMap<String, LinkedHashMap<Integer, LinkedHashMap<String,
Vector<String>>>>();
LinkedHashMap is still a Map data structure. It maps a unique key to a value. If you assign two different values to a key the second value will simply replace the first value assigned to that key.
Also imagine why do you need a Map of duplicated key? The sole purpose of Map is to provide a one to one relationship between key/value pair. It does not handle one to many relationship.
If you have to map a key with a list of values, use something like:
LinkedHashMap<String, List<..>>
This allows you to have one key maps to a list of values.

Java: Setting key of a hashmap explicitly and keeping reference to it

public static HashMap<ArrayList<Integer>, String> map = new HashMap<ArrayList<Integer>, String>();
public static ArrayList<ArrayList<Integer>> keys = new ArrayList<>(map.keySet());
Then in main
map.put(key, "c");
(assume key is a valid ArrayList). But keys still has size 0 after that.
How can I make the relationship of keys stronger so that it will be actually tied to the HashMap and contain all its keys.
The copy constructor of ArrayList copies all the keys in the map to the ArrayList but if you change the map after that point it will not be reflected.
I can think of 3 options:
write your own map implementation that embeds an ArrayList and keeps it up to date
update the ArrayList manually everytime you update the map
don't use an ArrayList at all (keySet() is there when you need to access the keys so I'm not sure why you would need one)
You can't.
Map.keySet() returns the Map's current key set, which you then load into your list. Changes to the map after that have no effect on the contents of the list.
Most people would just re-get the key set if needed. Why don't you just do that?

Concurrent modification issue in map

I am using a concurrent hashmap of structure
Map<Set<Date>, Map<String, Object>> SampleMap
The Map used inside the given map (Map<String, Object>) is also a concurrent hashmap,
but set is a only TreeSet type.
Still I get concurrent Modification exception when I add following line in logs,
logger.debug("sampleMap.keySet() + ". Size is " + sampleMap.keySet().size()");
and also in some other parts of same class dealing with this map.
This map is extensively used in Batch process by multiple threads to put and remove values in map and java version used is 1.5.
I think the exception is due to Treeset and also i find there is no similar implementation of concurrent handling collection for type Set.
It would be great if any one confirm whether my thinking over given issue is correct and also please suggest solution for this problem?
Since you need to be able to "modify" the key, you need to follow this pattern
// lock the collection
Map<String, Object> values = map.remove(key);
key = new TreeSet<String>(key);
// modify copy of key
map.put(key, values);
// unlock the collection.
As you are performing an operation which ConcurrentMap does not support, you have to use your own locking. You can use a plain HashMap or LinkedHashMap with synchronized or ReentrantReadWriteLock.
You can create a Concurrent set using
// Added in Java 1.6
Set<String> set = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
// or to be sorted
Set<String> set = Collections.newSetFromMap(new ConcurrentSkipListMap<String, Boolean>());
However, you can't change the contents of a key so what you should be using is
Set<String> key = Collections.unmodifiableSet(treeSet);
// or to be sure its not modified
Set<String> key = Collections.unmodifiableSet(new TreeSet<String>(treeSet));
A simple example of why you cannot change a key after using it in a Map.
Set<String> key1 = new TreeSet<String>();
Map<Set<String>, Boolean> map = new ConcurrentHashMap<Set<String>, Boolean>();
map.put(key1, true);
System.out.println("Is the map ok? "+map.containsKey(key1));
key1.add("hello");
System.out.println("Is the map ok? "+map.containsKey(key1));
prints
Is the map ok? true
Is the map ok? false
The common behaviour is that it can no longer see the key in the map. This is because the map places the key into a bucket based on its hashCode. If the hashCode changes, it can be in the wrong bucket so when it looks for it, it can't find it.

Categories