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());
}
}
}
Related
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.
I have a TreeMap, I wanted to iterate over it and print key-value pairs. But I dont want to start from the beginning, I want to start from a particular key-value pair.
Basically I want to do this -
TreeMap<String, String> treeMap = new TreeMap<String, String>();
//Populate it here
treeMap.get("key1");
//get the iterator to the treemap starting from the key1-value1 pair and iterate
I know how to do this if I want to iterate from start to end, but I dont find any answers to this.
You can do this with tailMap :
Iterator<String> iter = treeMap.tailMap("key1").keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
String value = treeMap.get(key);
// do your stuff
}
or
Iterator<Map.Entry<String,String>> iter = treeMap.tailMap("key1").entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,String> entry = iter.next();
// do your stuff
}
Use tailMap,
treeMap.tailMap(fromKey)
You can also use it like this;
for (Map.Entry<String, String> entry : treeMap.tailMap("key1").entrySet()) {
// Do something
}
I have question why I can't get this values
HashMap<String, P> users = new HashMap<String, P>();
users.put("john", new P("john"));
List<String> arenaUsers = new ArrayList<String>();
arenaUsers.add("john");
for (String user : arenaUsers) {
for (P p : users.get(user)) {
System.out.println(p.getName());
}
}
I got error:
Can only iterate over an array or an instance of java.lang.Iterable
But I can't iterate Map, How I can fix it?
here you class p does not implement Iterable so it can't be used inside the for loop. So to use it inside for loop you need to implement Iterable or use an existing collection which have already implemented Iterable i.e.
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> l =new ArrayList<String>();l.add("stack");l.add("overflow");
map.put("trying", l);
for(String ss: map.get("trying")){
System.out.println(ss);
}
Here i have used List which implements Iterable and can be used in side the for loop.
In Map for one key you will get only one value, thats the cause of
"Can only iterate over an array or an instance of java.lang.Iterable"
this happens in the second for loop, which is useless as its only one value
for (P p : users.get(user))
Instead do as:
for (String user : arenaUsers) {
if(users.containsKey(user))
System.out.println(users.get(user).getName());
}
}
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
}
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();
}
}