iterate through all the values of a key in hashtable java - java

Hashtable<Integer,String> ht = new Hashtable<Integer,String>();
ht.put(1,"student1");
ht.put(1,"student2");
How can I iterate through all values of "a single key"?
key:1
values: student1, student2

You need to use:
Hashtable<Integer, List<String>> ht = new Hashtable<Integer, List<String>>();
and add the new String value for a particular key in the associated List.
Having said that, you should use a HashMap instead of Hashtable. The later one is legacy class, which has been replaced long back by the former.
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
then before inserting a new entry, check whether the key already exists, using Map#containsKey() method. If the key is already there, fetch the corresponding list, and then add new value to it. Else, put a new key-value pair.
if (map.containsKey(2)) {
map.get(2).add("newValue");
} else {
map.put(2, new ArrayList<String>(Arrays.asList("newValue"));
}
Another option is to use Guava's Multimap, if you can use 3rd party library.
Multimap<Integer, String> myMultimap = ArrayListMultimap.create();
myMultimap.put(1,"student1");
myMultimap.put(1,"student2");
Collection<String> values = myMultimap.get(1);

A Hashtable doesn't store multiple values for a single key.
When you write ht.put(1, "student2"), it overwrites the value that goes with "1" and it is no longer available.

Hashtable doesn't allow multiple values for a key. When you add a second value to a key, you're replacing the original value.

If you want multiple values for a single key, consider using a HashTable of ArrayLists.

Related

Store the values without overwriting

I have a Map<String, Integer> e.g.
"aaa", 1
"bbb", 2
"ccc", 3
"aaa", 4
The problem is that the HashMap does not store all key and values, as I've understood, when i try add the last pair ("aaa", 4), it will not be added, instead of this, the value for "aaa" (I mean 1) will be overwritten on 4.
I know, that I could create class, where I could store these pairs, but I need another solution. (without creating a new class)
EDIT ------------------------------------
Actually I have much more pairs, and I do not have uniques String or Integers, I mean that, if even I have two similar pairs they will be stored
A map, by definition, will have distinct keys. If you add a key-value pair and the key already exists, the new key-value pair will overwrite the existing key-value pair.
For your scenario, when you have multiple values against a single key, you can explore the following options
Option 1 : Since your key-value pairs are not unique, it can be stored as list of pairs. For every key-value pair, you can create a pair and insert it into the list.
List<Pair<String, Integer>> data = new ArrayList();
Pair<String, Integer> item = new Pair("abc", 1);
data.add(item);
This option does not give you optimized lookup capabilities that comes with Map.
Option 2. Create a Map<String, List<Integer>>. You'll not be able to do simple put operations on the map anymore, but you will be able to store all the items corresponding to each key without loss of information as well as retrieve them faster.
Create a List:
if (!map.containsKey("aaaa")) {
map.put("aaaa", new ArrayList<Integer>());
}
List<Integer> aaaaValues = map.get("aaaa");
aaaaValues.add(1);
aaaaValues.add(4);
...
If your values are unieque, use them as keys.
You don't have to create class. You can use List<org.apache.commons.lang3.tuple.Pair<String, Integer>>
Also one way, override equals and hashCode where you speak that object is unique only if String and Integer parameter is unique in pair
Map<String, Integer> map = new HashMap<String, Integer>(){
#Override
public boolean equals(Object o)
{
// your realization
}
#Override
public int hashCode()
{
// your realization
}
};

For Each Loop in a Set

I have a HashTable with the following {4:1, 3:56, 4:3, 4:5, 9:89, etc.}
I then make the keys of this Table into a keyset by calling map.keySet().
How can I loop through that set to only output the values associated with the key of 4? I want the output to be 1,3,5, therefore I only want the values associated with the key 4? Is this possible, and if so how.
That's not how maps work. Maps typically only associate one value with each unique key value. So if you have a Map<Integer,Integer> myMap, calling myMap.put(4, newValue), where newValue is some integer, will overwrite the value that was previously mapped to 4. You can have duplicate values though, and you can print all known keys that have been mapped to that value in a map using the following loop.
for (Entry<Integer, Integer> entry : myMap.entrySet()) {
if (entry.getValue().equals(4)) {
System.out.println(entry.getKey());
}
}
A HashMap or a HashTable only maps a key to a value.
Option 1:
If you want to have multiple values for key store it as a list
Map<Integer, List<Integer>> myMap = new HashMap<>();
//To add value for a key
if (!myMap.containsKey(key)) {
myMap.put(new ArrayList<>());
}
myMap.get(key).add(value);
//Get
myMap.get(key); //This will give you the list of value for a given key and null if the key is not present
Option 2:
You can use Google Guava's MultiMap
You can use Google Guava Collections' MultiMap as it allows each key to associate with multiple values.
ListMultimap<String, String> multimap = ArrayListMultimap.create();
multimap.put(key, value);
Documentation can be found here: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html

Unable to retrieve multi line value using map.get()

I have a multi-line value that needs to be processed. I'm using the map.get() method to retrieve that value but it seems to be getting only the last line value.
Here's my code:
map = new LinkedHashMap();
updateMap("BUG", parser, map, bugRec);
map.put(nextBuildIdTagName, nextBuildId); // putting the new value in
String value = (String)map.get(nextBuildIdTagName); // This is where it is not working
nextBuildIdTagName already has a value, and the new value gets inserted as a new line. I need to be able to retrieve the existing value as well as the new value.
So from what I understand you want to store multiple values in the map under single key. Easiest way to do it (without using any external lib with multimap impl) is to create a map of lists like this:
Map<String, List<String>> map = new HashMap<>();
then when you add to map you can do sth like this:
if(!map.containsKey(nextBuildIdTagName)) {
map.put(nextBuildIdTagName, new ArrayList<>());
}
map.get(nextBuildIdTagName).add(nextBuildId);
then to get all the items and iterate over them
for(String value : map.get(nextBuildIdTagName)) {
// do sth to each line
}
In the javadoc for HashMap (of which LinkedHashMap is a subclass), it is clearly stated that: "If the map previously contained a mapping for the key, the old value is replaced". To store multiple values (the lines) for the same key, you'd need to do something like:
Map<String, List<String>> map = new Linked HashMap<>();
And the add to the list (which is the map value) the needes lines. Note: here I assumed your key to be a String, change its type as needed.
Source: http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#put(K,%20V)

How to create and push dynamic elements in HashMap

static Map<Integer,HashMap<String,HashMap<String,String>>> maps = new HashMap<Integer, HashMap<String,HashMap<String,String>>>();
I want to insert the elements inside the HashMap I declared above , the inner most hashmap has values ready which I can use , now I am using it like ,
static Map<String,String> values = new HashMap<String, String>();
maps.put(1, new HashMap<<new String("")>, values>());
How can I achieve this ?
static Map<String,String> values1 = new HashMap<String,String>();
static Map<String,Map<String,String>> values2 = new HashMap<String,Map<String,String>>();
values2.put("", values1);
maps.put(1,values2);
btw, if you have java 7, you can use:
Map<String,String> values1 = new HashMap<>();
and so on for others
In cases you have map inside a map (inside a map), consider using Apache MultiKeyMap.
Coding will be more intuitive
It will improve the readability of your code
It will prevent many if(map.get(key) != null) blocks you will probably have in your code.
Why not to have instance of HashMap. When you wan to insert new value, you need to have Integer, String, String key and String value.
You continuously select nested HashMaps according to keys and then insert value to the most inner HashMap.
map.get(key1).get(key2).insert(key3, value)

Retrieving the previous key-map value before it was overwritten in a HashMap

I have created a HashMap as per my code...
HashMap map=new HashMap();//HashMap key random order.
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
System.out.println("There are "+map.size()+" elements in the map.");
System.out.println("Content of Map are...");
Set s=map.entrySet();
Iterator itr=s.iterator();
while(itr.hasNext()){
Map.Entry m=(Map.Entry)itr.next();
System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
}
When I execute this code, the value for key=Saral is Android. Is there any way that I can get the previous value for this key, which was J2EE?
No, you can't have that with a standard HashMap. The easiest solution would be to store a List as value in the map though, and then you can add multiple items to the list (Btw you should use generic collections too). To simplify, you could use a helper method like this:
void addToMap(Map<String, List<String>> map, String key, String value) {
List<String> list = map.get(key);
if (list == null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(value);
}
Map<String, List<String>> map = new HashMap<String, List<String>>();
addToMap(map, "Amit", "Java");
addToMap(map, "Saral", "J2EE");
addToMap(map, "Saral", "Andriod");//same key but different value
addToMap(map, "Nitin", "PHP");
addToMap(map, "hj", "Spring1");
...
The helper method here is just an illustration - a full, robust implementation may need to include e.g. checks for duplicate values, depending on whether you allow them. If not, you may prefer using a Set instead of List.
Update
To print out the contents of this map, you need to use an embedded loop to iterate through the list of values for each map entry (btw you can use a foreach loop instead of an iterator):
for (Map.Entry<String, List<String>> m : map.entrySet())
{
for (String v : m.getValue())
{
System.out.println(m.getKey()+"\t"+v+"\t"+ m.hashCode());
}
}
A Map can contain at most one entry per key, so when you call map.put("Saral","Andriod"), the old "J2EE" value is removed. To support multiple values per key, you would need to maintain a Map<String, List<String>> or else a multi-map implementation such as Guava's Multimap.
As a side note I would recommend you start using generics, for example Map<String, String>, Iterator<String>, etc. for type safety at compile time.
The old value is overwritten (replaced). There will be only one mapping (entry) for one unique key. There fore it does not exist anymore so you can not retrieve it.
You cannot do this with standard implementations of Map that Java provides. However there are implementations of MultiMap (that's basically what you're after).
One example is this one from Google:
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html
Note that you won't be able to just get this one interface, you'll need a few classes along with it.
As other have said, this won't work with a standard Map. However, Google's Guava provides a MultiMap interface, which you can use to store multiple values with a single key.
Example of use:
Multimap<String,String> multiMap = ArrayListMultimap.create();
multiMap.put("color", "red");
multiMap.put("color", "blue");
System.out.println(multiMap.get("color")); //returns a ["red', "blue"] list

Categories

Resources