Multi-valued hashtable in Java - java

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());
}

Related

Java HashMap - Optimized way of appending a new value to a vector which is a value in a HashMap<String, Vector<String>>

A similar way to appending new element to a vector like in C++ :-
myHashMap[myKey].push_back(newElement); //push newElement to the value vector directly
The only way i can think of in Java is to get the vector from hashmap. Append the new string to the vector and then set the key again with the new vector.
myValue = myHashMap.get(myKey);
/**Check if the key exists
**/
//If exists
myValue.add(newElement);
myHashmap.put(myKey, myValue);
Is the second approach as fast as the previous and if not is there any other approach? Thanks
You do not have to put back the vector back in the map as you are already modifying the vector when adding to it.
myHashMap[myKey].push_back(newElement);
is achieved by
myHashMap.get(myKey)
.add(newElement);
(assuming myHashMap.get(myKey) does not return a null).
You can use computeIfAbsent in the Map interface to construct a vector object for a key processed for the first time. This is more elegant and does not require a if block.
myHashMap.computeIfAbsent(key, k -> new Vector<>())
.add(newElement);
The function (k -> new Vector<>()) is only executed if the myHashMap does not have a mapping for the key key. The nice thing about this is it returns the vector value of key so that we can chain the add call on it.
Firstly, if you care about performance in Java, use ArrayList instead of Vector. As the javadoc says:
As of the Java 2 platform v1.2, [Vector] was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized. If a thread-safe implementation is not needed, it is recommended to use ArrayList in place of Vector.
So, assuming we are using Java 8 (and ArrayList), there are two translations for the C++ code.
Version #1. Works for Java 5+
HashMap<String, ArrayList<String>> myMap = new HashMap<>();
...
ArrayList<String> list = myMap.get(myKey);
if (list == null) {
list = new ArrayList<>();
myMap.put(myKey, list);
}
list.add(newElement);
Version #2. Works for Java 8+
HashMap<String, ArrayList<String>> myMap = new HashMap<>();
...
myMap.computeIfAbsent(key, k -> ArrayList<>()).add(newElement);
Which will be faster? You would need to test it to be sure, but I think that the second version should be a bit faster because it avoids the second hashmap lookup in the put call.
And 1 line of code is neater than 6 lines. (YMMV for readability. It depends on the person reading the code, and how familiar they are with Java 8+ language features and APIs.)
You can do this in the same way in java.
myHashMap.get(key).add(newValue)
Because in the hashmap the reference of list (or you can say it vector) is stored as value. So modifying the content of List will not influence the reference. You can imagine this reference likes 64bits address of a vector in c++.

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();

return key for common values in hash map

I have a hash map. Multiple keys have same value. What is the best way to find the
keys for repeated Values without iterating. ?
Reading this documentation it feels there is no function for it.
NOTE: Key | Value pair are of Int type
One way or the other, you will end up iterating the collection. The iteration may be hidden from view in some library, but it would necessarily be there.
You can easily write a simple method that does what you need:
public static <K,V> Set<K> keysOfDupValues(Map<K,V> m) {
Set<K> res = new HashSet<K>();
Map<V,K> seen = new HashMap<V,K>();
for (Map.Entry<K,V> e : m.entrySet()) {
V v = e.getValue();
K k = e.getKey();
if (seen.containsKey(v)) {
res.add(k);
res.add(seen.get(v));
} else {
seen.put(v, k);
}
}
return res;
}
Demo on ideone.
There is no way to find all the keys for a value without iterating on the Map in standard JDK API.
You can use the Guava library, either by :
using Maps.filterValues that returns entries whose values satisfy a Predicate
converting to a Guava Multimap and use Multimaps.invert
using a BiMap.
It's really not possible. The very implementation of method containsValue(), in the superclass java.util.AbstractMap iterates through the values.
So, you'll have to itarate through the values to achieve that.
You can take a look at the implementation of containsValue() to have a hint on how to do that.
If you get that map read made from code you don't have control on, then you have no other choice but to iterate on the map.
In any case, you can avoid the issue of doing several iterations by building a reverse map, which will boil down to a multimap, but since there is no specific class definition for that pattern in Java, you will have to build it using a map and lists.
Each time you need to include a new pair <k,v> in your original map, you also include the reverse pair <v,k> in your reverse map. If v as a key (ie. the original value) doesn't yet exist in the reverse map, you map it to a list solely containing k as the value (ie. the original key). If the key v already exists in the reverse map, then you simply push the value k to the existing list.
When you need to know which keys map to a given value in your original map, you query for the value in the reverse map, and get the list of keys.
The Java tutorial on maps includes a section on implementing multimaps using maps.
This solution should be very effective if you have control on the map creation process. However, if the map is created and regularily updated by some outside mechanism, it will be of little gain.
If you can only control the creation of the map, but not its update, you could implement a new class exposing the Map interface, which internally holds the reverse map as well and update it when a new pair is inserted/removed, or support a notification mechanism to let your code know the map has been changed and how.
Try change
File newxmlfile = new File(Environment.getExternalStorageDirectory()
+ ts);
to
File newxmlfile = new File(Environment.getExternalStorageDirectory()
+ "/"+ts);

Double table in Java

I need a double table from which I get two values from a key or index. I have seen this question already and I want to know what would be a better approach considering also performance.
1) Create a HashMap on this way:
HashMap<Integer, HashMap<String, String>> = ...;
I don't know how to put values inside this the put method, I have this and Eclipse gives me an error prueba.put(0, new Hashtable<"Hi", "Bye">); As you can see I have never used something like this before I am sure is a simple question.
2) Create a HashMap on this way:
HashMap<Integer, YourFancyDatatype>
So I create a class which pack the two or more values I want to have in one Object inside a single key or index.
Which would perform better ? Also if you can help me about how to use number 1) approach. The HashMap will have about 20000 entries.
Thank you very much for your time and help :)
You would want something with a single key and a collection of values. I would suggest using Apache's MultiMap, as they already implement this functionality for you.
Your first approach uses the same datastructure as provided by the Guava's HashBasedTable so you can use it instead.
But if you want the best performance you could try to use something based on arrays (e.g. Guava's ArrayTable)
Anyway I suggest to make some simple performance tests to check which solution performs better.
It you want to do an "in-line" put, you can do this:
prueba.put(0, new HashMap<String, String>() {{put("Hi", "Bye");}});
This employs an anonymous subclass of HashMap that has an instance block that loads the values.
Note that this will create one extra class for the JVM (called MyClass$1 or similar).
I don't know how to put values inside this the put method, I have this
and Eclipse gives me an error prueba.put(0, new Hashtable<"Hi",
"Bye">); As you can see I have never used something like this before I
am sure is a simple question.
Firstly, Hashtable<String, String> is not a subtype of HashMap<String,String>. your HashMap expects a HashMap<String, String> as a value. either insert a hashmap into values or change your hashmap declaration to :
HashMap<Integer, ? extends Map<String, String>> = ...;
however your 2nd approach is more object oriented. so i'd recommend using 2nd approach
The second one would probably be easier in your case in this way
HashMap<Integer, HashMap<String, FancyDataType>> h= ...;
this is how you'll have to insert the data
h=HashMap<Integer, FancyDataType> new Hashtable<Integer,FancyDataType>();
numbers.put(0, new FancyDataType("o","x"));
numbers.put(1, new FancyDataType("t","y"));
numbers.put(1, new FancyDataType("q","z"));
/// ...so one for all 20000
Assuming FancyDataType is something like
class FancyDataType{
String k,v;
FancyDataType(String k,String v){
this.k=k;this.v=v;
}
}

how to store data in Java with key name and its value?

I have a situation where i want to store data in an object with a key and its value. The key name is the same, but the value is changed. i tried to use hash Map but it also does not support this. it overwrites all values and gives me only the recent value in pair.
my question is: are there any classes or methods that can help me sort out this problem?
What data structure to use
If the requirement is to store multiple values for a single key, then using a multimap would be a good option.
One implementation of such a multimap is the Multimap from the Google Guava library.
The Multimap interface in Guava has several implementations depending on the requirements for the multiplicity and ordering of the keys and values.
Choosing an implementation
A simple implementation is the HashMultimap, where the values mapped by a key will not allow duplicates, and the ordering of the keys are not determinant.
The ArrayListMultimap preserves the order of the values mapped to a key, in the order at which they were mapped to the key.
If you need to keep track of multiple values, you could possibly use a List value in the Map. You could use the assumption that the last value in the List is the most recent value, if that meets your requirements.
Creating such a map would be done like this (though your key and value types don't have to be Strings, they could be whatever classes you're using):
Map<String, List<String>> map = new HashMap<String, List<String>>();
Then to get the latest value for a given key, you'd need to get the last element of the corresponding list:
List<String> list = map.get(key);
String value = null;
if (list != null) {
value = list.get(list.size() - 1);
}
To add a value to the Map, you'd need to add logic to create a new list if no value exists for a new key, otherwise add the new value to the end of the list:
if (map.get(key) == null) {
List<String> list = new ArrayList<String>();
list.add(value);
map.put(key, list);
}
else {
map.get(key).add(value);
}
Java's standard collections don't include a class for so-called "multimaps", but several other collection libraries offer this feature. Eg:
MultiMap from Apache Commons
Multimap from google-collections

Categories