HashMap of HashMap-> output Problems - java

Having the following HashMap:
HashMap <String, HashMap <Integer, ArrayList <Reservation> >> buffer;
I'm going to output every single value of every single key of the two hashmaps. How can I do?
I have already written this portion of the code:
HashMap map=mod.getAllRecords();
for (Object key: map.keySet()) {
String Date=key.toString();
Object map2=map.get(key);
for(Object Key : ??){//<--------------
}

Easiest way I know is to write three for-loops - first for the key elements themselves which are already strings, second for the integers within the HashMap inside the first HashMap and third for the values inside each array of the second HashMap:
for (String key: map.keySet()) {
System.out.println(key); //prints the strings
HashMap <Integer, ArrayList <Reservation> > map2 = map.get(key);
for(Integer key2 : map2.keySet()){
System.out.println(key2); //prints the integers
for (int i=0;i<map2.get(key2).size();i++) {
System.out.println(map2.get(key2)[i]); //prints everything in the array
}
}
}

Given
Map<String, Map<Integer, List<Reservation>> map = new HashMap<>();
You can print out all the reservations, sans map keys as follows.
map.values().stream()
.flatMap(m->m.values().stream())
.flatMap(List::stream)
.forEach(System.out::println); // prints each reservation
the first stream, streams the inner map (values of the outer map)
the flatMap replaces that stream with the stream of the inner values (the lists)
the last flatMap streams the lists.
The above presumes that the Reservation class has overridden toString
If you want to print out all the keys too, you can do it like this. I indented the output to provide a key/value hierarchy.
map.forEach((k,v)-> {
System.out.println(k);
v.forEach((k1,v1)-> {
System.out.println(" " + k1);
v1.forEach(res->System.out.println(" " + res));
});
});

Related

How to search efficiently return all the values for keys which are in a arraylist

I am having an arraylist which contains a list of numbers. I want to get all the values from the HashMap which has the keys which are in the array list.
For example say the array list contains 1,2,3,4,5,6,7,8,9 list
I want to get all the values for the keys 1,2,3,4,5,6,7,8,9 map
So currently I am implementing
for (i=0;i<list.size;i++){
map_new.put(list.get(),map.get(list.get()))
}
Is there any efficient way to do this?
Your code basically assumes that map.get(list.get()) always returns a value, you can try the following code which first filters the not null values from the list object and then adds to the new Map:
Map<String, Integer> newMap = list.stream().
filter(key -> (map.get(key) != null)).//filter values not present in Map
collect(Collectors.toMap(t -> t, t -> map.get(t)));//now collect to a new Map
In case, if map.get(list.get()) returns null, your code creates a Map with null values in it for which you might end up doing null checks, which is not good, rather you can ensure that your newly created Map always contains a value for each key.
Assuming the signature of list and the map are as following
List<Integer> list;
Map<Integer, Integer> map;
You can use following
for(int a : list){
Integer b = map.get(a);
if(b != null)
// b is your desired value you can store in another collection
}
Which is similar to the procedure you have already used.
As you can access the map in O(1) so the complexity of this code will be O(listsize)
There is not much you can do for efficiency. Still couple of small things you can do considering code example you have given above:
1) Change your for loop to
for(Long num : list)
instead of iterating using index, this will reduce you get calls over list.
2) You can update the existing map , so that you even do not need to iterate.
map.keySet().retainAll(list);
for(Long key: map.keySet()) {
System.out.println(map.get(key));
}
With this existing map will contain only those data whose keys are present in list, but you should use it carefully depending upon rest of the code logic.
You can capitalize on the fact that the keyset of a map is backed by the map itself and modifications to the keyset will reflect back to the map itself. This way, you can use the retainAll() method of the Set interface to reduce the map with a single line of code. Here is an example:
final Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1, "A");
m.put(2, "B");
m.put(3, "C");
m.put(4, "D");
m.put(5, "E");
final List<Integer> al = Arrays.asList(new Integer[] { 2, 4, 5 });
System.out.println(m);
m.keySet().retainAll(al);
System.out.println(m);
This will output:
{1=A, 2=B, 3=C, 4=D, 5=E}
{2=B, 4=D, 5=E}

Updating a map in java

I have the following maps :
Map <String,String> m; // contains part details
Map <String,String> n; // contains part details
Map <String,String> o; // the new map that contains both m and n.
I want copy the values from m into o first.
I then want to loop though n and compare keys against o. If key from n, does not exist in o then put key/value it to o.
I tried the below, but the the the second step is not working (values are not copying)
for (Map.Entry<String, String> entry : m.entrySet())
{
String key = entry.getKey();
String value =entry.getValue();
o.put(key, value);
}
for (Map.Entry<String, String> entry : n.entrySet())
{
String key = entry.getKey();
String value =entry.getValue();
for (Map.Entry<String, String> entry1 : o.entrySet())
{
String key1 = entry.getKey();
if(key1 != key)
{
o.put(key,value);
}
}
}
Consider using Map#containsKey(). You can also iterate over a keyset, not over the entryset.
for (String key: n.keySet())
{
if (!o.containsKey(key))
o.put(key,n.get(key));
}
This should work.
I think the problem was you were using direct comparing of Strings, which is not sufficient in your case (almost never), use String#compareTo() method instead.
Why you don't use ready methods? You do not have to write all manually ;).
1) Method putAll() copies all values from one map to the second.
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#putAll(java.util.Map)
2) Method containsKey() and only one loop.
You don't have to loop through o.
Just use o.containsKey() method
In second inner for loop "String key1 = entry.getKey();" it should be "String key1 = entry1.getKey();"
mistaken between entry and entry1
o.putAll(m); // put all m into o
n.keySet().removeAll(o.keySet()); // Remove all duplicates from n
o.putAll(n); // Now add all filtered n to o

Using HashMap for getting repeating occurences

I have a HashMap which is populated with String and Integer:
Map<String, Integer> from_table;
from_table = new HashMap<String, Integer>();
Next i want to get all the keys of items which there value (the Integer) is above x.
For example all the keys which their value is over 4.
Is there a fast method for doing that?
Thnaks!
public static void printMap(Map mp) {
for(Map.Entry pairs : mp.entrySet()) {
if(pairs.getValue() >= 4)
{
System.out.println(pairs.getKey());
}
}
}
Well, iterate over the key-value pairs and collect keys where values meet the criteria
//collect results here
List<String> resultKeys= new ArrayLIst<String>();
//hash map iterator
Iterator<String> it = from_table.keySet();
while(it.hasNext()) {
//get the key
String key= it.next();
/get the value for the key
Integer value= from_map.get(key);
//check the criteria
if (value.intValue() > x) {
resultKeys.add(key);
}
}
Not in standard Java. Guava has method called filter doing exactly this as a one-liner (+ the predicate).
As the above solution states there is nothing faster than just looping through, but an alternative solution would be to edit the function to put something in the map and have it check if there are 4 or more items, if there are it adds it to a new list with only objects with a count of more than 4

Sorted map not outputting sorted. Do I understand maps.

I have been reading up on maps and understand some of the differences in tree maps and hash, sorted maps. I was trying to get a map to be sorted when outputting it.
What I needed to be able to do was:
Take a text file and read in the content.
Break it into separate words. Use the words as the key and the value as how many times the key occurs in the txt file.
If the word is at the end of a sentence I am to make it a separate key. E.g., my and my. are two separate keys.
My problem is that no matter if I declare it as a tree, hash or sorted map, I can't get it to output/iterate through in an ordered way. I wanted it to output with the highest occurring value first, but I can't even get it to output with the key in any order.
public static Map<String, Integer> createDictionary(String _filename)
{
TreeMap<String, Integer> dictionary = new TreeMap<String, Integer>(); // Changed Hash to _______
try {
FileReader myFileReader=new FileReader(_filename); // File reader stream open
BufferedReader myBuffReader=new BufferedReader(myFileReader);
String str = "\0";
while (str != null) { // While there are still strings in the file
str = myBuffReader.readLine(); // We read a line into the str variable
if (str != null) { // Make sure its not the last line/EOF
// System.out.println(str); // Used for testing.
StringTokenizer myTokenStr=new StringTokenizer(str," \t"); // Create a StringToken obj from the string
while (myTokenStr.hasMoreTokens()) {
String tokStr = myTokenStr.nextToken(); // Each token is put into an individual string
// System.out.println(tokStr);
if (dictionary.containsKey(tokStr)) {
int value = dictionary.get(tokStr); // Add one to the integer value
// dictionary.remove(tokStr); // Was doing this way but just using put method works
// dictionary.put(tokStr, value + 1);
dictionary.put(tokStr, value + 1);
}
else {
dictionary.put(tokStr, 1); // Add the string as the key with an int value of one for the value
}
}
}
}
myBuffReader.close(); // Close stream
myFileReader.close(); // Close stream
}
catch (FileNotFoundException e) {
System.out.println("File Not Found");
}
catch (IOException e) { }
// System.out.println(dictionary.entrySet());
return dictionary;
}
Your map is sorted alphabetically, not by number of occurrences. You need to postprocess the map after the initial parsing. I would suggest:
Parse file into HashMap<String, Integer>
Iterate through HashMap, and add elements to a TreeMap<Integer, Set<String> > (see below).
Output the TreeMap.
You can achieve step 2. by something like:
TreeMap<Integer, Set<String> > treeMap = new TreeMap<Integer, Set<String> > ();
for (Map.Entry<String, Integer> entry: hashMap) {
Set<String> set = treeMap.get(entry.value());
if (set == null) {
set = new TreeSet<String>();
treeMap.put(entry.value(), set);
}
set.add(entry.key());
}
Using TreeSet here sorts the words with same number of occurrences alphabetically, you could use any other Set or List though.
For descending order in step 3.:
for (Map.Entry<Integer, Set<String> > entry: treeMap.descendingMap())
for (String word: entry.getValue())
System.out.println(String.format("%d: %s", entry.getKey(), word));
That should do it.
This is the documentation for TreeMap, lifted from its Javadoc:
public class TreeMap extends AbstractMap
implements NavigableMap, Cloneable, Serializable
A Red-Black tree based NavigableMap implementation. The map is sorted according
to the natural ordering of its keys, or by a Comparator provided at map creation
time, depending on which constructor is used.
In your case, the keys would be strings, and you should expect that iteration will reveal the map to be sorted according to their 'natural order'. Here's an example of the output generated by a TreeMap consisting of String keys and Integer values:
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("Hello", Integer.valueOf(8));
map.put("Abraham", Integer.valueOf(81));
map.put("Smell", Integer.valueOf(-1));
map.put("Carpet", Integer.valueOf(4));
map.put("Sex", Integer.valueOf(23));
for(String key: map.keySet()) {
System.out.printf("Map entry %s: %d\n", key, map.get(key));
}
Output:
Map entry Abraham: 81
Map entry Carpet: 4
Map entry Hello: 8
Map entry Sex: 23
Map entry Smell: -1
As you can see, iterating over the map's keys produces as ordered result. This order is defined by the natural order of String. Unfortunately, you cannot implement a SortedMap that sorts on values, which is what I believe you want to do. You can however, sort the entries in the Map outside of it. See more details in this other SO post: TreeMap sort by value.
Map is a kind of messy abstraction for this sort of thing, but I'm going to throw out Guava's Multiset as a way to address this use case, as it's expressly designed for "counting occurrences of things."
In particular,
return Multisets.copyHighestCountFirst(HashMultiset.copyOf(listOfWords));
returns a Multiset that iterates over elements in order of descending frequency in listOfWords.
There are many questions on SO, by the way, relating to ordering maps by values instead of keys, but I prefer this solution.

When using a HashMap are values and keys guaranteed to be in the same order when iterating?

When I iterate over the values or keys are they going to correlate? Will the second key map to the second value?
No, not necessarily. You should really use the entrySet().iterator() for this purpose. With this iterator, you will be walking through all Map.Entry objects in the Map and can access each key and associated value.
to use the entrySet that #Cuchullain mentioned:
Map<String, String> map = new HashMap<String, String>();
// populate hashmap
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// your code here
}
You want to use this, LinkedHashMap, for predicable iteration order
public class Test {
public static void main(String[] args) {
HashMap <String,String> hashmap = new HashMap<String,String>();
hashmap.put("one", "1");
hashmap.put("two", "2");
hashmap.put("three", "3");
hashmap.put("four", "4");
hashmap.put("five", "5");
hashmap.put("six", "6");
Iterator <String> keyIterator = hashmap.keySet().iterator();
Iterator <String> valueIterator = hashmap.values().iterator();
while(keyIterator.hasNext()) {
System.out.println("key: "+keyIterator.next());
}
while(valueIterator.hasNext()) {
System.out.println("value: "+valueIterator.next());
}
}
}
key: two
key: five
key: one
key: three
key: four
key: six
value: 2
value: 5
value: 1
value: 3
value: 4
value: 6
Both values() and keySet() delegate to the entrySet() iterator so they will be returned in the same order. But like Alex says it is much better to use the entrySet() iterator directly.
I agree with pmac72. Don't assume that you'll get ordered values or keys from an unordered collection. If it works time to time it is just pure hazard. If you want order to be preserved, use a LinkedHashMap or a TreeMap or commons collections OrderedMap.
The question confused me at first but #Matt cleared it up for me.
Consider using the entrySet() method that returns a set with the key-value pairs on the Map.
Map<Integer, Integer> a = new HashMap<Integer, Integer>(2);
a.put(1, 2);
a.put(2, 3);
for (Map.Entry<Integer, Integer> entry : a.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
This outputs:
1 => 2
2 => 3
3 => 3
I second #basszero. While
for (Map.Entry<Integer, Integer> entry : a.entrySet())
will work, I find using a data structure that does this automatically is nicer. Now, you can just iterate "normally"
HashMap's keySet method returns a Set, which does not guarantee order.
HashMap's values() method returns a Collection, which does not guarantee order.
That said, the question was "are they going to correlate" so technically the answer is maybe, but don't rely on it.

Categories