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.
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.
Here is an example method:
public void loadStuff(Map<String, Object> someMap) {
Map<String, Object> myMap = new HashMap<String, Object>();
//I now load defaults here first
myMap.put("One", someObject);
myMap.put("two", someObject);
myMap.put("three", someObject);
//Now I put the entire someMap so that only those keys that are present in someMap are overridden in myMap and others remain default.
myMap.putAll(someMap);
}
Now, is there a better way of doing these redundant puts as the number of defaults in my scenario are a lot.
Consider creating an initial map with your defaults in, and then use:
// Alternatively, you could use clone()
Map<String, Object> myMap = new HashMap<String, Object>(defaults);
myMap.putAll(someMap);
Aside from anything else that means you can load the "default map" from a properties file or whatever.
If you really don't like the fact that it will put each value twice, you could write a loop to check for each key - but I'd personally just use the above code. It's simple and it should work fine.
Are you wanting to preload a single answer for just a few items, or are you wanting a default for all unfound keys? If you want to change the default answer from null to something else, see this question. If you're wanting to preload some items, then you'll need to put all of them, though it's best not to embed the values in code like that; use a for loop instead that iterates over a single official list of the keys.
If you are going to be initializing blank copies of this Map frequently, it will make more sense to have a template Map that each myMap is constructed from; either a HashMap wrapped as unmodifiable or a Guava ImmutableMap are good choices there. Constructing from a preexisting Map instead of copying all of the elements into the new HashMap is much more efficient since the new one knows how big to make itself.
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?
Is it possible to have multiple values for the same key in a hash table? If not, can you suggest any such class or interface which could be used?
No. That's kind of the idea of hash tables.
However, you could either roll your own with a Map<YourKeyObject, List<YourValueObject>> and some utility methods for creating the list if it's not present, or use something like the Multimap from Google Collections.
Example:
String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"
Note that Multimap is not an exact equivalent of the home-baked solution; Hashtable synchronizes all its methods, while Multimap makes no such guarantee. This means that using a Multimap may cause you problems if you are using it on multiple threads. If your map is used only on one thread, it will make no difference (and you should have been using HashMap instead of Hashtable anyway).
Values of a hash table is Object so you can store a List
In a hashtable, one would use a key/value pair to store information.
In Java, the Hashtable class accepts a single value for a single key. The following is an example of an attempt to associate multiple values to a single key:
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("Answer", "42");
ht.put("Hello", "World"); // First value association for "Hello" key.
ht.put("Hello", "Mom"); // Second value association for "Hello" key.
for (Map.Entry<String, String> e : ht.entrySet()) {
System.out.println(e);
}
In an attempt to include multiple values ("World", "Mom") to a single key ("Hello"), we end up with the following result for printing the entries in the Hashtable:
Answer=42
Hello=Mom
The key/value pair of "Hello" and "World" is not in the Hashtable -- only the second "Hello" and "Mom" entry is in the Hashtable. This shows that one cannot have multiple values associate with a single key in a Hashtable.
What is really needed here is a multimap, which allows an association of multiple values to a single key.
One implementation of the multimap is Multimap from Google Collections:
Multimap<String, String> mm = HashMultimap.create();
mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");
for (Map.Entry<String, String> e : mm.entries()) {
System.out.println(e);
}
This is similar to the example above which used Hashtable, but the behavior is quite different -- a Multimap allows the association of multiple values to a single key. The result of executing the above code is as follows:
Answer=42
Hello=Mom
Hello=World
As can be seen, for the "Hello" key, the values of "Mom" and "World" associated with it. Unlike Hashtable, it does not discard one of the values and replace it with another. The Multimap is able to hold on to multiple values for each key.
Rather than give yet another multipmap answer, I'll ask why you want to do this?
Are the multiple values related? If yes, then it's probably better that you create a data structure to hold them. If no, then perhaps it's more appropriate to use separate maps.
Are you keeping them together so that you can iterate them based on the key? You might want to look for an alternative indexing data structure, like a SkipList.
Just make your own:
Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();
To add:
public void add(String key, Object o) {
List<Object> list;
if (multiMap.containsKey(key)) {
list = multiMap.get(key);
list.add(o);
} else {
list = new ArrayList<Object>();
list.add(o);
multiMap.put(key, list);
}
}
As others pointed out, no. Instead, consider using a Multimap which can map many values for the same key.
The Google Collections (update: Guava) library contains one implementation, and is probably your best bet.
Edit: of course you can do as Eric suggests, and store a Collection as a value in your Hashtable (or Map, more generally), but that means writing unnecessary boilerplate code yourself. When using a library like Google Collections, it would take care of the low-level "plumbing" for you. Check out this nice example of how your code would be simplified by using Multimap instead of vanilla Java Collections classes.
None of the answers indicated what I would do first off.
The biggest jump I ever made in my OO abilities was when I decided to ALWAYS make another class when it seemed like it might be even slightly useful--and this is one of the things I've learned from following that pattern.
Nearly all the time, I find there is a relationship between the objects I'm trying to place into a hash table. More often than not, there is room for a class--even a method or two.
In fact, I often find that I don't even want a HashMap type structure--a simple HashSet does fine.
The item you are storing as the primary key can become the identity of a new object--so you might create equals and hash methods that reference only that one object (eclipse can make your equals and hash methods for you easily). that way the new object will save, sort & retrieve exactly as your original one did, then use properties to store the rest of the items.
Most of the time when I do that, I find there are a few methods that go there as well and before I know it I have a full-fledged object that should have been there all along but I never recognized, and a bunch of garbage factors out of my code.
In order to make it more of a "Baby step", I often create the new class contained in my original class--sometimes I even contain the class within a method if it makes sense to scope it that way--then I move it around as it becomes more clear that it should be a first-class class.
See the Google Collections Library for multimaps and similar such collections. The built-in collections don't have direct support for this.
What you're looking for is a Multimap. The google collections api provides a nice implementation of this and much else that's worth learning to use. Highly recommended!
Simple. Instead of
Hashtable<Key, Value>, use Hashtable<Key, Vector<Value>>.
You need to use something called a MultiMap. This is not strictly a Map however, it's a different API. It's roughly the same as a Map<K, List<V>>, but you wont have methods like entrySet() or values().
Apart from the Google Collections there is a apache Commons Collection object
for MultiMap
Following code without Google's Guava library. It is used for double value as key and sorted order
Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();
for( int i= 0;i<15;i++)
{
List<Object> myClassList = multiMap.get((double)i);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put((double) i,myClassList);
}
myClassList.add("Value "+ i);
}
List<Object> myClassList = multiMap.get((double)0);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put( (double) 0,myClassList);
}
myClassList.add("Value Duplicate");
for (Map.Entry entry : multiMap.entrySet())
{
System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
}