I have a HashMap
inside a HashMap
. I want to print the elements in the HashMap
according to the size of elements in the inner HashMap
. So the element with the highest number of elements should print first. I'm new to HashMaps and Currently got stuck here.
This is the HashMap and how I'm printing it:
Map<String, Map<String, Integer>> states = new ConcurrentHashMap<String, Map<String, Integer>>();
for(Entry<String, Map<String, Integer>> entry : states.entrySet()) {
System.out.println("State:" entry.getKey());
Map<String, Integer> tempMap = entry.getValue();
for(Entry<String, Integer> innerEntry : tempMap.entrySet()) {
System.out.println("City:" innerEntry.getKey() " Count:" innerEntry.getValue());
}
System.out.println();
}
The output that I'm currently getting:
State:Texas
City:Austin Count:1
State:Hawaii
City:Honolulu Count:1
City:Kihei Count:1
City:Maui Count:1
State:California
City:Newport Beach Count:1
The output I need:
State:Hawaii
City:Honolulu Count:1
City:Kihei Count:1
City:Maui Count:1
State:Texas
City:Austin Count:1
State:california
City:Newport Beach Count:1
CodePudding user response:
Since ConcurrentHashMap makes no guarantees about ordering, you have to sort your map be getting entrySet and sort them then re-put into a LinkedHashMap
Map<String, Map<String, Integer>> sortedStates = new LinkedHashMap<String, Map<String, Integer>>();
states.entrySet().stream()
.sorted(new Comparator<Map.Entry<String, Map<String, Integer>>>() {
public int compare(Map.Entry<String, Map<String, Integer>> mapA, Map.Entry<String, Map<String, Integer>> mapB){
return mapB.getValue().size() - mapA.getValue().size();
}
})
.forEachOrdered(mapInner -> sortedStates.put(mapInner.getKey(), mapInner.getValue()));
CodePudding user response:
- create a size_map -> Map<Integer, List> size_map = new HashMap<Integer, List>();
- This is to store store number of cities as key and states as the value. Note here states are stored in a list because multiple states can have same number of cities.
Make a list (size_list) out of keys of map in point 1. (Keys are number of cities for different states). Order this list in descending order
While iterating your "states" Hashmap, use size_list as a lookup and fetch the list of states with the current size from size_map HashMap. Basically use size_list as a lookup.
Note - this will increase your overhead and performance might not be great.
Map<String, Map<String, Integer>> states = new ConcurrentHashMap<String, Map<String, Integer>>();
//create size HashMap -- store number of cities as key and value would be list of states
Map<Integer, List<String>> size_map = new HashMap<Integer, List<String>>();
for(Map.Entry<String, Map<String, Integer>> entry : states.entrySet())
{
int size = entry.getValue().size();
String state = entry.getKey();
if(size_map.containsKey(size))
{
List<String> retreived_list = size_map.get(size);
retreived_list.add(state);
size_map.put(size, retreived_list);
}
else
{
List<String> retreived_list = new ArrayList<String>();
retreived_list.add(state);
size_map.put(size, retreived_list);
}
}
//create a list out of size_map keys and sort it in descending order
List<Integer> size_list = new ArrayList<Integer>(size_map.keySet());
Collections.sort(size_list, Collections.reverseOrder());
//index will be current index in size_list, fetch states list from size_map and look for the same state in the original "state" hashmap
int index =0;
for(Map.Entry<String, Map<String, Integer>> entry : states.entrySet())
{
int current_size = size_list.get(index);
List<String> states_list = size_map.get(current_size);
for(String s : states_list)
{
System.out.println("State:" s);
Map<String, Integer> tempMap = states.get(s);
for(Map.Entry<String, Integer> innerEntry : tempMap.entrySet()) {
System.out.println("City:" innerEntry.getKey() " Count:" innerEntry.getValue());
}
}
index ;
System.out.println();
}
CodePudding user response:
You can use Streams API for sorting before print it out:
Comparator<Entry<String, Map<String, Integer>>> entryComparator =
Comparator.comparingInt((Entry<String, Map<String, Integer>> entryOne) -> entryOne.getValue().size());
for(Entry<String, Map<String, Integer>> entry : states.entrySet().stream().sorted(entryComparator.reversed()).collect(
Collectors.toList())) {
System.out.println("State:" entry.getKey());
Map<String, Integer> tempMap = entry.getValue();
for(Entry<String, Integer> innerEntry : tempMap.entrySet()) {
System.out.println("City:" innerEntry.getKey() " Count:" innerEntry.getValue());
}
System.out.println();
}
CodePudding user response:
HashMap makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time. Using LinkedHashMap instead and that will look like:
Map sortedMap = new LinkedHashMap();
originalHashMap.entrySet().stream()
.sorted(Comparator.comparingInt(e -> e.getValue().size()))
.forEachOrdered(e -> sortedMap.put(e.getKey(), e.getValue()));
Now, expected sorted map is sortedMap