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

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.

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

Compare keys with llist of values Java

Assuming the TreeMap<String,List> one and its copy as bellow,
i want to compare all keys in the first one with all values in the second one. If a key has no match in values, as AUF_1060589919844_59496 and AUF_1421272434570_1781 in this case, i want to get the key and its values back.
{AUF_1060589919844_59496=[AUF_1086686287581_9999,
AUF_1086686329972_10049, AUF_1079023138936_6682],
AUF_1087981634453_7022=[AUF_1421268533080_1741, AUF_1421268568003_1743],
AUF_1421268533080_1741=[AUF_1421268719761_1776],
AUF_1421272434570_1781=[AUF_1087981634453_7022]}
copy of above
{AUF_1060589919844_59496=[AUF_1086686287581_9999,
AUF_1086686329972_10049, AUF_1079023138936_6682],
AUF_1087981634453_7022=[AUF_1421268533080_1741, AUF_1421268568003_1743],
AUF_1421268533080_1741=[AUF_1421268719761_1776],
AUF_1421272434570_1781=[AUF_1087981634453_7022]}
What I understand from your problem is to get key which are not there in values and its value also. I think there is no need to create copy of it. I am posting a code snippet, I think this will certainly help you
Map<String, List<String>> map = new HashMap<String, List<String>>(); //Add elements in map
Collection<List<String>> list = map.values();
List<String> values = new ArrayList<String>();
for (List<String> listValues : list) {
values.addAll(listValues);
}
for (String key : map.keySet()) {
if (!values.contains(key)) {
System.out.println("key ---->" + key);
System.out.println("Values ------->");
for (String value : map.get(key)) {
System.out.println(value);
}
}
}
If my assumption is correct you want all the keys that are not values;
well this is very dirty way of doing it.
Set<String> keys= new HashSet<String>(one.keySet()); //ensure we don't mess up with the actual keys in the Map
for(List list : one.values()){
keys.removeAll(list); //remove all those Keys that are in values
}
// print out keys that are not values
System.out.println(keys);
Using set will make life easy, as it doesn't contain duplicates, and we can remove values very quicky (using removeAll() method)

Can't figure out how to retrieve objects in a map

I have a
Map<String, List<String>> myMap;
I'm having a hard time retrieving the objects in the List:
For example I can retrieve from the Map
String myString = myMap.get("Toyota").toString();
but how do I retrieve from the List?
Lets say that the List contains all the models for each car brand. How can I retrieve only the item 0 in that that List?
Thanks
myMap.get("Toyota").get(0) - That should do it.
The reason is that you ask myMap the value that is pointed by the key "Toyota". As you defined in your definitions, the values are always of type List<String> which means that the call myMap.get("Toyota") returns a List<String> object. When you do a get(0) call you actually call the get method of List<String>
You need to retrieve the List and then its contents :
//myMap.get(key).get(listIndex);
// myMap.get("Toyota"); // gets the List object
myMap.get("Toyota").get(0);
Hence , you need to use Map#get() and then List#get().
The statement myMap.get("Toyota") will return the List type which is value for the key Toyota. You can get the first element of list using myMap.get("Toyota").get(0)
Basically when you use a Map and want to retrieve values based on certain key, you can iterate over the Map and retrieve them as follows :
for (final Entry<String, List<String>> entry : myMap.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
}
As you can see, inside the for loop, you have both key and the value. You can do the further processing here after.

How to put multiple values in Map from a list

I have a list gotitems.
ArrayList<String> gotitems = new ArrayList<String>();
i need to put that list in a hashmap called map.
Map<String,String> map = new HashMap<String,String>();
i had tried this :
for(String s:gotitems){
map.put("a",s);
}
gotitems contains :
First
Second
Third
But the output of :
System.out.println(map.values());
gives :
Third
Third
Third
i had even tried this :
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
but this is also not working.
What am i doing wrong here ?
As per Map put(K,V) method docs
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value.
You are ovverriding the key each time here .
for(String s:gotitems){
map.put("a",s);
}
change the key each time and try like
for(String s:gotitems){
map.put(s,s);
}
This is because you are putting all the items in the map against the same key "a"
map.put("a");
You need to store each element against a unique key so add something like this:
int count = 0;
for(String s:gotitems){
map.put("a" + count,s);
count++;
}
You are trying to put three Strings in the map under the same key "a". Try to use unique keys for your values.
You're putting all your items in the Map with the same key: "a".
You should have a unique String key for each value.
For instance:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Map<String, String> map = new LinkedHashMap<String, String>();
for (String s: list) {
map.put(s, s);
}
System.out.println(map);
Output:
{one=one, two=two, three=three}
Note the LinkedHashMap here: it maintains the order in which you put your key/value pairs.
Edit Of course if your List does not have unique values, moving its values as keys to a Map will overwrite some of the Map's values. In that case you want to ensure your List has unique keys first, or maybe use a Map<Integer, String> with the index of the List's value as key to the Map, and the actual List value as value to the Map.
When you write
for(String s:gotitems){
map.put("a",s);
}
you will trash any existing entry in the map held against the key "a". So after your iteration, your map will contain just one entry corresponding to the last iterated value in gotitems.
To use a map effectively you need to consider what your keys will be. Then use map.put(myKeyForThisItem, s) instead. If you don't have an effective scheme for the keys then using a map is pointless as one tends to use the keys to extract the corresponding values.
As for your second approach, it would be helpful if you could define "it is not working" a little clearer: perhaps iterate through the map and print the keys and values.
Please note that in a map, a key can point to at most one value. In your case, you are doing the following mappings:
"a" -> "one"
then you overwrite it as
"a" -> "two"
then you overwrite it as
"a" -> "three"
remember: a key can point to at most one value. However, a value can be pointed at by multiple keys.
This is wrong:
for(String s:gotitems){
map.put("a",s);
}
Since you are using "a" common key for all values, last inserted key-value pair would be preserved, all previous ones would be overridden.
This is also not correct:
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
you are putting n*n times into map, though you want only n (gotitems.size()) items into map.
First decide on key which you want to use in map, copying List into Map one approach could be use index as key:
for(int j=0;j<gotitems.size();j++){
map.put("KEY-"+j,gotitems.get(j));
}
Output should be:
KEY-0 First
KEY-1 Second
KEY-2 Third
I have reproduce your codes. The problem is that you are assigning the same key to different value. This should work.
import java.util.*;
public class testCollection{
public static void main(String[] args){
ArrayList<String> gotitems = new ArrayList<String>();
gotitems.add("First");
gotitems.add("Second");
gotitems.add("Third");
Map<String,String> map = new HashMap<String,String>();
String x = "a";
int i = 1;
for(String s:gotitems){
map.put(x+i,s);
i++;
}
System.out.println(map);
}
}

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