HashMap updating ArrayList - java

I'm just starting to learn to use HashMap and reading the java tutorial, but I'm having trouble.
I'm trying to update the List inside a HashMap but I want to get the List of that key, is there a way to update a specific List of the key instead of having to make...5 different Lists and updating those?
HashMap<String, ArrayList<String>> mMap = new HashMap<String, ArrayList<String>>();
ArrayList<String> list = new ArrayList<String>();
mMap.put("A", list);
mMap.put("B", list);
mMap.put("C", list);
mMap.put("D", list);
Iterator iter = mMap.entrySet().iterator();
if (mMap.containsKey("A"))
{
Map.Entry mEntry = (Map.Entry) iter.next();
list.add("test");
mMap.put("A",list);
System.out.println(mEntry.getKey() + " : " + mEntry.getValue());
}
else if (mMap.containsKey("B"))
{
Map.Entry mEntry = (Map.Entry) iter.next();
list.add("entry");
mMap.put("B",list);
System.out.println(mEntry.getKey() + " : " + mEntry.getValue());
}

You could use something like:
mMap.get("A").add("test");
mMap.get("B").add("entry");

Like #Tudor said, use mMap.get("A").add("foo");
You put the same exact list into each map entry. You initial lines should be
mMap.put("A", new ArrayList());
mMap.put("B", new ArrayList());
...
mMap.put("Z", new ArrayList());
Alternatvely, write a method that checks on the fly
public synchronized void myAdd(String key, String value) {
List<String> there = mMap.get(key);
if (there == null) {
there = new ArrayList<String>();
mMap.put(key, there);
}
there.add(value);
}

you probably mean:
HashMap<String, List<String>> mMap = new HashMap<String, List<String>>();
mMap.put("A", new ArrayList<String>());
mMap.put("B", new ArrayList<String>());
mMap.put("C", new ArrayList<String>());
mMap.put("D", new ArrayList<String>());
if (mMap.containsKey("A"))
{
mMap.get("A").add("test");
System.out.println(mEntry.getKey() + " : " + mEntry.getValue());
}
else if (mMap.containsKey("B"))
{
mMap.get("B").add("entry");
System.out.println(mEntry.getKey() + " : " + mEntry.getValue());
}
...
I wonder if you really need those containsKey checks either!
HTH!

I think that in your case you can use Google Guava's Multimap and ListMultimap interfaces and ArrayListMultimap implementation.
Choosing right collection (in link there are only standard collections but Multimap is right in this case) makes code more readable:
ListMultimap<String, String> myMultimap = ArrayListMultimap.create();
myMultimap.put("A", "test");
myMultimap.put("B", "entry");
then myMultimap.get("A") gives you list (ArrayList instance in fact) with one element: "test", while myMultimap.get("C") gives you empty list.
Comparing to Map<String, List<String>> approach:
you don't have to initialize "C" key with empty list for it,
you don't have nulls checks (no NullPointerExceptions),
you don't have to do other checks such as myMap.containsKey("A"),
you write less code,
so your code is less bug-prone,
etc., etc.
P.S. Instead of:
HashMap<String, ArrayList<String>> mMap = new HashMap<String, ArrayList<String>>();
use interfaces, not classes when using collections i.e.:
Map<String, List<String>> mMap = new HashMap<String, List<String>>();
and even better Guava's "static constructors" (you don't repeat code):
Map<String, List<String>> mMap = Maps.newHashMap()
when knowledge about implementation is not necessary.

If you add the same list as a value with different keys, in your case keys A,B,C, and D all point to the same list, and access and update the list through one key the changes will then be visible in all the lists. Each key points to the same list structure.
If you want the lists to be different you need to use different for different keys you need to use a different list.
You could automate the process, say by making your own insert method that clones the given list.

I would do something like this.
private final ReentrantLock lock = new ReentrantLock();
Map<String ,List<String>> mMap=new HashMap<>();
public void myAdd(String key, String value) {
try {
lock.lock();
List<String> there =mMap.get(key)==null?new ArrayList<>():mMap.get(key);
there.add(value);
mMap.put(key, there);
}finally {
lock.unlock();
}
}

Related

How to add a value to a list of values for a single key in a hashmap (Java)

I have written this:
HashMap<String, String> map1 = new HashMap<String, String>();
Map<String, ArrayList<String>> map2 = new HashMap<String, ArrayList<String>>();
i am trying to allow more then 1 value for each key in a hashmap. so if the first key is '1', i want to allow '1' to be paired with values '2' and '3'.
so it be like:
1 --> 2
|--> 3
but when I do:
map2.put(key, value);
it gives error that says "incompatible types" and it can not be converted to ArrayList and it says the error is at the value part of the line.
If you are using Java 8, you can do this quite easily:
String key = "someKey";
String value1 = "someValue1";
String value2 = "someValue2";
Map<String, List<String>> map2 = new HashMap<>();
map2.computeIfAbsent(key, k -> new ArrayList<>()).add(value1);
map2.computeIfAbsent(key, k -> new ArrayList<>()).add(value2);
System.out.println(map2);
The documentation for Map.computeIfAbsent(...) has pretty much this example.
In map2 you need to add ArrayList (you declared it as Map<String, ArrayList<String>> - the second one is the value type) only, that's why it gives you incompatible types.
You would need to do initialize the key with an ArrayList and add objects to it later:
if (!map2.containsKey(key)) {
map2.put(key, new ArrayList<String>());
}
map2.get(key).add(value);
Or you could use Multimap from guava, then you can just map2.put and it won't overwrite your values there but add to a list.
You are little bit away from what you are trying to do.
Map<String, ArrayList<String>> map2 = new HashMap<String, ArrayList<String>>();
this will allow only String as key and an ArrayList as value. So you have to try something like:
ArrayList<String> value=new ArrayList<String>();
value.add("2");
value.add("3");
map2.put("1", value);
When retrieving you also have to follow ans opposite procedure.
ArrayList<String> valueTemp=map2.get("1");
then you can iterate over this ArrayList to get those values ("2" and "3");
Try like this. //use list or set.. but set avoids duplicates
Map<String, Set<String>> map = new HashMap<>();
Set<String> list = new HashSet<>();
// add value to the map
Boolean b = map.containsKey(key);
if (b) {
map.get(key).addAll(list);
} else
map.put(key, list);
}
You can not add different values in same key in Map. Map is override the value in that key. You can do like this way.
Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
ArrayList<String> list=new ArrayList<String>();
list.add("2");
list.add("3");
map.put("1", list);
first add value in array list then put into map.
It is all because standard Map implementations in java stores only single pairs (oneKey, oneValue). The only way to store multiple values for a particular key in a java standard Map is to store "collection" as value, then you need to access this collection (from Map) by key, and then use this collection "value" as regular collection, in your example as ArrayList. So you do not put something directly by map.put (except from creating the empty collection), instead you take the whole collection by key and use this collection.
You need something like Multimap, for example:
public class Multimap<T,S> {
Map<T, ArrayList<S>> map2 = new HashMap<T, ArrayList<S>>();
public void add(T key, S value) {
ArrayList<T> currentValuesForGivenKey = get(key);
if (currentValuesForGivenKey == null) {
currentValuesForGivenKey = new ArrayList<T>();
map2.get(key, currentValuesForGivenKey);
}
currentValuesForGivenKey.add(value);
}
public ArrayList<S> get(T key) {
ArrayList<String> currentValuesForGivenKey = map2.get(key);
if (currentValuesForGivenKey == null) {
currentValuesForGivenKey = new ArrayList<S>();
map2.get(key, currentValuesForGivenKey);
}
return currentValuesForGivenKey;
}
}
then you can use it like this:
Multimap<String,String> map2 = new Multimap<String,String>();
map2.add("1","2");
map2.add("1","3");
map2.add("1","4");
for (String value: map2.get("1")) {
System.out.println(value);
}
will print:
2
3
4
it gives error that says "incompatible types" and it can not be converted to ArrayList and it says the error is at the value part of the line.
because, it won't automatically convert to ArrayList.
You should add both the values to list and then put that list in map.

HashMap, return key and value as a list

I have an homework to do, so I have finished the script but the problem is with the values.
The main code is (I cannot change it due to homework) :
List<String> result = cw.getResult();
for (String wordRes : result) {
System.out.println(wordRes);
}
It have to return:
abc 2
def 2
ghi 1
I have no idea how to handle that.
Now only shows:
abc
def
ghi
I have no idea how to change this method getResult to return with the value of the hashmap as well without changing the first main code.
public List<String> getResult() {
List<String> keyList = new ArrayList<String>(list.keySet());
return keyList;
}
The hashmap is: {abc=2, def=2, ghi=1}
And list: Map<String, Integer> list = new HashMap<String, Integer>();
Please help me if you know any resolution.
I think that now that you have learned about keySet and valueSet, your next task is to learn about entrySet. That's a collection of Map.Entry<K,V> items, which are in turn composed of the key and the value.
That's precisely what you need to complete your task - simply iterate over the entrySet of your Map while adding a concatenation of the value and the key to your result list:
result.add(entry.getKey() + " " + entry.getValue());
Note that if you use a regular HashMap, the items in the result would not be arranged in any particular order.
You need to change this line:
List<String> keyList = new ArrayList<String>(list.keySet());
to:
//first create the new List
List<String> keyList = new List<String>();
//iterate through the map and insert the key + ' ' + value as text
foreach(string item in list.keySet())
{
keyList.add(item+' '+list[item]);
}
return keyList;
I haven't written java in a while so compiler errors might appear, but the idea should work
Well simplest way make an ArrayList and add as #dasblinkenlight said...
Iterator<?> it = list.entrySet().iterator();
while (it.hasNext()) {
#SuppressWarnings("rawtypes")
Map.Entry maps = (Map.Entry) it.next();
lista.add(maps.getKey() + " " + maps.getValue());
}
}
public List<String> getResult() {
List<String> temp = lista;
return temp;
}
If you want to iterate over map entries in order of keys, use an ordered map:
Map<String, Integer> map = new TreeMap<String, Integer>();
Then add your entries, and to print:
for (Map.Entry<String, Ibteger> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}

Appending data to a subarray instead of having it overwritten with the latest entry

I currently have a Map that is configured as such.
Map<String, ArrayList<Object>> map = new HashMap<String, ArrayList<Object>>();
where the purpose is to be able to have a setup much like the following:
array("foo"->array(1->"aaa",2->"bbb",3->"ccc"),
"bar"->array(1->"aaa",2->"bbb",3->"ccc"),
"bah"->array(1->"aaa",2->"bbb",3->"ccc"),
)
The problem I'm running into is that I can create the root array fine, but it will do the following, using the previous example as illustration
array("foo"->array(3->"ccc"),
"bar"->array(2->"bbb"),
"bah"->array(3->"ccc"),
)
What I'm trying to find out is how I can append the sub array as opposed to having it overwritten. I assume it's easily done I'm just missing something obvious.
What you need is to first check if map has an entry for a particular key. If not, then add an empty arraylist.
After that, get that arraylist from map and add object to that arraylist.
Map<String, ArrayList<Object>> map = new HashMap<String, ArrayList<Object>>();
String first = "FIRST";
if (map.get(first) == null){
map.put(first, new ArrayList<Object>());
}
map.get(first).add(new Object());
If you will print above map, you will get desired output.
Appending to Array's in Java is not possible because they have a fixed length. I suggest you use ArrayList instead.
HashMap<String, ArrayList<Object>> map = new HashMap<String, ArrayList<Object>>();
public void appendToMap(String key, Object o)
{
if(!map.containsKey(key))
{
map.put(key, new ArrayList<Object>());
}
map.get(key).add(o);
}
Afterwards just set your values:
appendToMap("foo", "aaa");
appendToMap("foo", "bbb");
// and so on...
You can just create a method to add to the sub-array, and create it if it doesn't exists :
Map<String, ArrayList<Object>> map = new HashMap<String, ArrayList<Object>>();
addToArray(map, "foo", "aaa");
addToArray(map, "foo", "bbb");
addToArray(map, "foo", "ccc");
addToArray(map, "bar", "aaa");
// ...
And the method would be :
private static void addToArray(final Map<String, ArrayList<Object>> map, final String key, final Object object) {
if (!map.containsKey(key))
map.put(key, new ArrayList<Object>());
map.get(key).add(object);
}
If you only need to store Strings in you array, you can use an ArrayList<String> instead of your ArrayList<Object>.
Switch to String instead of Object (if the list would always contain strings)
Map<String, List<String>> map = new HashMap<String, List<String>>();
Then add to your Map as follows
// check if a List already exists
if ((list = map.get("foo")) == null) { // if !exists,
list = new ArrayList<String>(1); // CREATE a new List
list.add("aaa");
map.put("foo", list); // ADD the new List to Map
} else { // if exists,
list.add("aaa"); // ADD to the existing List
}

ArrayList<HashMap<String,String>> keys iteration/output to arrays

If I have a type
ArrayList<HashMap<String,String>> keys = functionWhichReturnsThisType();
How can I iterate through so that I end up with all <1st string of hashmap> in a string array and likewise <2nd string of hashmap> into another string array.
I have tried to use the iterator but the hierarchy in the data type is confusing me.
appPrefs = new AppPreferences(context.getApplicationContext());
ArrayList<HashMap<String,String>> keys = appPrefs.getDownloadUrls();
ArrayList<String> urls = new ArrayList<String>();
ArrayList<String> filenames = new ArrayList<String>();
Iterator myIterator = keys.keySet().iterator();
while(myIterator.hasNext()) {
urls.add((String)myIterator.next());
filenames.add((String)keys.get(myIterator.next()));
}
If the order doesn't matter, you can try
for (HashMap<String, String> map : keys) {
urls.addAll(map.keys());
filenames.addAll(map.values());
}
If you want to keep the order, you can try
for (HashMap<String, String> map : keys) {
for (Map.Entry<String, String> entry : map.entrySet()) {
urls.add(entry.getKey());
filenames.add(entry.getValue());
}
}
OK, I'll walk through your sample code and show where you're running into issues, and suggest how you can get it to work.
ArrayList<HashMap<String,String>> keys = appPrefs.getDownloadUrls();
This (above) is fine - but remember keys is an ArrayList. It's a list of HashMap objects, but it's still a list
ArrayList<String> urls = new ArrayList<String>();
ArrayList<String> filenames = new ArrayList<String>();
These are good, but in typical Java, it would be better to have List<String> urls = new ArrayList<String>(); to try and keep your variables using interfaces instead of concrete implementations.
Iterator myIterator = keys.keySet().iterator();
while(myIterator.hasNext()) {
This won't work, because keys is an ArrayList, and a list does not have a keySet() you want to do:
Iterator<HashMap<String,String> listIterator = keys.iterator();
while(listIterator.hasNext()) {
HashMap<String,String> map = listIterator.next();
Iterator<String> myIterator = map.keySet().iterator();
while(myIterator.hasNext()) {
Or, even better would be to use the Java 1.5 for(each) loop:
for( Map<String,String> map : keys ) {
for( String url : map.keySet() ) {
--
urls.add((String)myIterator.next());
The above would work, once you get myIterator to be an iterator over the map, rather than the list.
filenames.add((String)keys.get(myIterator.next()));
But this won't for 2 reasons
Because keys is still a list.
If you call next on an iterator twice then you get 2 different objects.
You need to have:
String url = myIterator.next();
urls.add(url);
filenames.add(map.get(url));
Or, if you use the for(each) loop I suggested above, then you can skip that first line.
Hope that helps - if something's unclear please add a comment.
Note: solilo's solution is a lot simpler and is a good way to do it, my answer is here to help you see where you were running into trouble.
This method will work for you extract first and second strings
private void getFirstAndSecondStrings(ArrayList<HashMap<String,String>> keys){
ArrayList<String> firstStrings = new ArrayList<String>();
ArrayList<String> secondStrings = new ArrayList<String>();
for (HashMap<String, String> map : keys) {
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pairs = (Map.Entry)iterator.next();
firstStrings.add((String)pairs.getValue());
secondStrings.add((String)pairs.getKey());
}
}
}

java multi mapping arraylist

Is it possible to map key to Multi Dimensional Array List. Some thing like following example..
Map<K,V>
Where K is key for list of alphabet and V is a multi dimensional array list or normal array list that stores list of word. Some thing like a application that reads a dictionary file. I want to see an example. Example can be anything related to Map and Multi Dimensional Array-list. Or is there any other efficient way to implement collection? I have never used such implementations so if there is already a thread related to mine QA please post the link.
You can always do Map<String, <List<String>>. e.g.
Map<String, List<String>> multimap = new HashMap<String, List<String>>();
String key = "asdf";
List<String> values = Arrays.asList("foo", "bar");
multimap.put(key, values);
You can also use the Multimap<String, String> interface in Google Guava - might be a better fit for your needs. It simplifies the coding somewhat -
Multimap<String, String> multimap = new ArrayListMultimap<String, String>();
String key = "asdf";
multimap.put(key, "foo");
multimap.put(key, "bar");
You can use Guava's Multimap's if you want to associate multiple values with a single key. You need ArrayListMultimap for your specific case.
Example
ListMultimap<String, String> dict= new ArrayListMultimap<String, String>();
dict.put("key 1", "value 1");
dict.put("key 1", "value 2");
dict.put("key 2", "value 1");
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());
}

Categories