Store the values without overwriting - java

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

Related

Java - Adding another String value to existing HashMap Key without overwriting?

I was wondering if someone would be able to help with regards to adding another String value to an existing key within a HashMap in Java?
I understand that you can add a Key-Value pair using the this.put("String", "String") method. However, it overwrites the existing value, whereas I would like multiple values stored and paired, with the same key?
Thanks for your help.
What are you hoping to achieve here?
A Map (the HashMap) in your case is a direct "mapping" from one "key" to another value.
E.g.
"foo" -> 123
"bar" -> 321
"far" -> 12345
"boo" -> 54321
This means that if you were to try:
myHashMap.get("foo");
It would return the value 123 (of course, the type of the value you return can be anything you want).
Of course, this also means that any changes you make to the value of the key, it overrides the original value you assigned it, just like changing the value of a variable will override the original one assigned.
Say:
myHashMap.put("foo", 42);
The old value of "foo" in the map would be replaced with 42. So it would become:
"foo" -> 42
"bar" -> 321
"far" -> 12345
"boo" -> 54321
However, if you need multiple String objects that are mapped from a single key, you could use a different object which can store multiple objects, such as an Array or a List (or even another HashMap if you wanted.
For example, if you were to be using ArrayLists, when you are assigning a value to the HashMap, (say it is called myHashMap), you would first check if the key has been used before, if it hasn't, then you create a new ArrayList with the value you want to add, if it has, then you just add the value to the list.
(Assume key and value have the values you want)
ArrayList<String> list;
if(myHashMap.containsKey(key)){
// if the key has already been used,
// we'll just grab the array list and add the value to it
list = myHashMap.get(key);
list.add(value);
} else {
// if the key hasn't been used yet,
// we'll create a new ArrayList<String> object, add the value
// and put it in the array list with the new key
list = new ArrayList<String>();
list.add(value);
myHashMap.put(key, list);
}
You can do like this!
Map<String,List<String>> map = new HashMap<>();
.
.
if(map.containsKey(key)){
map.get(key).add(value);
} else {
List<String> list = new ArrayList<>();
list.add(value);
map.put(key, list);
}
Or you can do the same thing by one line code in Java 8 style .
map.computeIfAbsent(key, k ->new ArrayList<>()).add(value);
Would you like a concatenation of the two strings?
map.put(key, val);
if (map.containsKey(key)) {
map.put(key, map.get(key) + newVal);
}
Or would you like a list of all the values for that key?
HashMap<String,List<String>> map = new HashMap<String,List<String>>();
String key = "key";
String val = "val";
String newVal = "newVal";
List<String> list = new ArrayList<String>();
list.add(val);
map.put(key, list);
if (map.containsKey(key)) {
map.get(key).add(newVal);
}
As others pointed, Map by specification can have only one value for a given key. You have 2 solutions:
Use HashMap<String, List<String>> to store the data
Use Multimap which is provided by 3rd party Google Collections lib
As described in Map interface documentation Map contains a set of keys, so it is not capable of containing multiple non-unique keys.
I suggest you to use lists as values for this map.
Store value as list under map So if key is test and there are two values say val1 and val2 then key will be test and value will be list containing val1 and val2
But if your intention is to have two separate entries for same key, then this is not Map is designed for. Think if you do map.get("key"), which value you expects
You could use Map<String, Collection<String>> but adding and removing values would be cumbersome . Better way is using guava Multimap - a container that allows storing multiple values for each key.
You can't directly store multiple values under a single key, but the value associated with a key can be any type of object, such as an ArrayList, which will hold multiple values. For example:
import java.util.ArrayList;
import java.util.HashMap;
public class HashMapList {
HashMap<String, ArrayList<String>> strings = new HashMap<String, ArrayList<String>>();
public void add(String key, String value) {
ArrayList<String> values = strings.get(key);
if (values == null) {
values = new ArrayList<String>();
strings.put(key, values);
}
values.add(value);
}
public ArrayList<String> get(String key) {
return strings.get(key);
}
public static void main(String[] argv) {
HashMapList mymap = new HashMapList();
mymap.add("key", "value1");
mymap.add("key", "value2");
ArrayList<String> values = mymap.get("key");
for (String value : values) {
System.out.println(value);
}
}
}
it's impossible,because String is immutable if you use the String as the key of map the same key's value has the same hashcode value.

iterate through all the values of a key in hashtable 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.

Merging Map of LinkedHashMap

I have two Map of LinkedHashMap in this format==> Map<String,LinkedHashMap<String,String>> both m1 & m2 have same key values, How we combine this m1 & m2 and make m3 with all elements.
Note :Can you some one give psuedocode I will implement it.Thanks.
Input is like below format:
m1={1={rollno=1,name=chris,height=7ft},2={rollno=2,name=stephen,height=6ft}}
m2={1={rollno=1,name=chris,weight=65},2={rollno=2,name=stephen,weight=73}}
Output :
m3={1={rollno=1,name=chris,height=7ft,weight=65},2={rollno=2,name=stephen,height=6ft,weight=73}}
What I tried :
private static Map<String, LinkedHashMap<String, String>> mergeMap(Map<String,LinkedHashMap<String, String>> m1, Map<String, LinkedHashMap<String, String>> m2) {
Map<String,LinkedHashMap<String, String>> newMap = new LinkedHashMap<String, LinkedHashMap<String, String>>(m1);
for (Map.Entry<String, LinkedHashMap<String, String>> entry : m2.entrySet()) {
LinkedHashMap<String, String> t1=newMap.get(entry.getKey());
newMap.putAll(m2);
}
System.out.println("ouput :"+newMap);
return newMap;
}
You can follow the steps below to merge the maps:
First create a newMap, passing first map - map1 as parameter. You have to use the overloaded constructor - LinkedHashMap(Map) for that. Now you have a map with all the elements of map1. Half of your job is done.
Map<String, Map<String, String>> newMap = new LinkedHashMap<>(map1);
Then you need to move elements from 2nd map to the newMap. For that, you would need to iterate over map2. You can use Map#entrySet() method to iterate over each entry in map2. You would then use Map.Entry#getKey() and Map.Entry#getValue() methods to get the key and value respectively for each entry.
For each key in map2, get the current value from newMap, and merge the value of map2, with the value in newMap. Both the values are Map. You can use Map#putAll() method to merge the two maps. It will automatically ignore the already available keys, and add the extra key-value pair.
Now, after resolving the above issue, you should consider changing your data structure. You should create a class say Person, to store all those attributes, and maintain a Map<Integer, Person>, where key will be rollNo.
What you have shown is just what you have. If you could explain some other details like, how and from where did you get those maps, and why would you possibly have the attributes of same person distributed in two different maps, may be we can help you better to formulate the data structure properly. Having a nested Map might be handled if you have small set of data, but if you have larger set of data, you will face difficult in handling them. You should certainly follow Object Oriented Approach.
You should use java object to store complete information.
like
class Student{
int rollNo;
String name;
String height;
String weight;
}
And store your elements like
Map<Integer,Student> map = new HashMap<Integer,Student>();
it will be much easy to merge and store and manage element like this

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

What is the best datastructure to use in Java for a "multidimensional" list?

I need a dictionary-like data structure that stores information as follows:
key [value 1] [value 2] ...
I need to be able to look up a given value by supplying the key and the value I desire (the number of values is constant). A hash table is the first thing that came to my mind but I don't think it can be used for multiple values. Is there any way to do this with a single datastrucuture rather than splitting each key-value pair into a separate list (or hash table)? Also I'd rather not use a multi-dimensional array as the number of entries is not known in advance. Thanks
I'm not sure what you mean about your list of values, and looking up a given value. Is this basically a keyed list of name-value pairs? Or do you want to specify the values by index?
If the latter, you could use a HashMap which contains ArrayLists - I'm assuming these values are String, and if the key was also a String, it would look something like this:
HashMap<String, ArrayList<String>> hkansDictionary = new HashMap<String, ArrayList<String>>();
public String getValue (String key, int valueIdx) {
ArrayList<String> valueSet = hkansDictionary.get(key);
return valueSet.get(valueIdx);
}
If the former, you could use a HashMap which contains HashMaps. That would look more like this:
HashMap<String, HashMap<String, String>> hkansDictionary
= new HashMap<String, HashMap<String, String>>();
----
public String getValue (String key, String name) {
HashMap<String, String> valueSet = hkansDictionary.get(key);
return valueSet.get(name);
}
You could make a class that holds the two key values you want to look up, implement equals() and hashcode() to check/combine calls to the underlying values, and use this new class as the key to your Map.
I would use
Map<Key,ArrayList<String>> map = new HashMap<Key,ArrayList<String>>
where you define Key as
public class Key{
private String key;
private String value;
//getters,setters,constructor
//implement equals and hashcode and tostring
}
then you can do
Key myKey = new Key("value","key");
map.get(myKey);
which would return a list of N items
You can create a multidimensional array by first declaring it, then creating a method to ensure that new value keys are initialized before the put. This example uses a Map with an embedded List, but you can have Maps of Maps, or whatever your heart desires.
I.e., you must define your own put method that handles new value initialization like so:
private static Map<String, List<USHCommandMap>> uSHCommandMaps = new HashMap<String, List<USHCommandMap>>();
public void putMemory() {
if (!uSHCommandMaps.containsKey(getuAtom().getUAtomTypeName()))
uSHCommandMaps.put(getuAtom().getUAtomTypeName(), new ArrayList<USHCommandMap>());
uSHCommandMaps.get(getuAtom().getUAtomTypeName()).add(this);
}

Categories

Resources