How to sort HashMap by referring another HashMap - java

I have two HashMap in Java.
First one contains a key and its value. Where second contains an evaluation index (order) of that keys. I want to sort the first map by referring to the second map.
First HashMap <key, value>
<"C","ccc">
<"D","ddd">
<"A","aaa">
<"B","bbb">
Second HashMap <key, value>
<"0","A">
<"1","B">
<"2","C">
<"3","D">
Result should be
<"A","aaa">
<"B","bbb">
<"C","ccc">
<"D","ddd">
Looping this two map and checking comparing keys is simple but not efficient. Any efficient idea?

You can use Java Stream API. First, sort the second map entrySet by key then map second map's value as key and get first map's value by value of the second map and then collect as LinkedHashMap using Collectors.toMap
secondMap.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.collect(Collectors.toMap(Map.Entry::getValue, k -> firstMap.get(k.getValue()),
(x, y) -> y, LinkedHashMap::new));
If you use LinkedHashMap/TreeMap ordered by key for the second map then you don't need to sort the keys. See demo here

First of all HashMap is not ordered collections. The key-value pairs in HashMap are ordered based on the value of hashCode() result of keys. So I would say you can't keep sorted values in HashMap.
Instead, you can use LinkedHashMap - it will be ordered with order of insertion.
And for your solution, i would do:
HashMap<String, String> firstMap = ...
HashMap<String, String> secondMap = ...
LinkedHashMap<String, String> orderedMap = new LinkedHashMap<>();
for (int i = 0; i < secondMap.size(); ++i) {
String key = secondMap.get(String.valueOf(i));
orderedMap.put(key, firstMap.get(key));
}
Did not run this code, but it should work.
Alternatively, you can use TreeMap that is ordered based on Comparable interface of the keys.
And to answer what is better to use - TreeMap or LinkedHashMap - depends on how actually you are using this map later. In most cases LinkedHashMap is enough, although if you need to, for example, get the closest greater element to some key, then TreeMap is a choice.
There are some comparison between HashMap and TreeMap
What is the difference between a HashMap and a TreeMap?

Traverse the values of secondMap and collect the related key, value set in the map:
Map<String, String> result = secondMap.values().stream()
.collect(Collectors.toMap(Function.identity(), firstMap::get, (x,y)-> x, LinkedHashMap::new));
Try this:
Map<String, String> firstMap = new HashMap<>();
firstMap.put("C", "ccc");
firstMap.put("D", "ddd");
firstMap.put("A", "aaa");
firstMap.put("B", "bbb");
Map<String, String> secondMap = new HashMap<>();
secondMap.put("0", "A");
secondMap.put("1", "B");
secondMap.put("2", "C");
secondMap.put("3", "D");
Map<String, String> result = secondMap.values().stream()
.collect(Collectors.toMap(Function.identity(), firstMap::get, (x,y)-> x, LinkedHashMap::new));
System.out.println(result);

Related

How could I combine two hash maps of <String, Integer> to one HashMap of <HashMap<String, String>, Integer>?

HashMap<String1, Integer1> and HashMap<String2, Integer2> to HashMap<HashMap<String1,String2> , Integer1+Integer2>
see hashmap contains Map(Key, Value) so if you want to merge the hashmap then you are changing the key.
so if you want to add multiple keys then you can do it with
Map<Map.Entry<String,String>, Integer> map = new HashMap<>();
map.put(Map.entry("onekey", "2nd Keys"), 0);

How to group values of map into lists based on key with java streams?

Say I have mappings from Strings to a Mapping from Strings to int, such as
Map<String, Map<String, Integer>> myMap1 = new HashMap<>();
myMap1.put("A", Map.of("X", 1))
myMap1.put("B", Map.of("Y", 1))
Map<String, Map<String, Integer>> myMap2 = new HashMap<>();
myMap2.put("B", Map.of("Y", 3))
I would like to merge these mappings such that we get a mapping where the key is the inner map's key, and the value would be the average of the inner maps values of the same keys.
So the output to the example above would be
{"X" : 1, "Y", 2}
We can discard the outer map's key altogether.
What is the nicest way to do this with java. I thought there might be some nice way to do it with Collectors.groupBy method but I am quite inexperienced with this.
I’m going to assume there might be more than two maps, so let’s make a List out of them:
Collection<Map<String, Map<String, Integer>>> myMaps =
List.of(myMap1, myMap2);
Then we can use flatMap on the values() of each Map, which gives us a stream of Map<String, Integer> maps.
We can obtain the entrySet() of each of those, then apply flatMap to the streams of those entry sets, to give us a single Stream of Map.Entry<String, Integer> objects, which we can then group.
There is a groupingBy method which takes a second Collector for customizing the values of the groups, by collecting all of the grouped values seen. We can use that to get our averages, using an averaging collector.
Map<String, Double> averages =
myMaps.stream().flatMap(map -> map.values().stream()) // stream of Map<String, Integer>
.flatMap(innerMap -> innerMap.entrySet().stream()) // stream of Map.Entry<String, Integer>
.collect(Collectors.groupingBy(Map.Entry::getKey, // group by String key
Collectors.averagingInt(Map.Entry::getValue))); // value for each key = average of its Integers

How to iterate hashmap in reverse order in Java

I am trying this for some hour but not finding any best approach to achieve iteration of hashmap in reverse order, this is the hashmap I have.
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
for(Integer key : map.keySet()) {
List<String> value = map.get(key);
List<Map<String,?>> security = new LinkedList<Map<String,?>>();
for(int ixy = 0; ixy < value.size()-1; ixy++){
security.add(createItem(value.get(ixy), value.get(ixy+1)));
}
adapter.addSection(Integer.toString(key), new SimpleAdapter(getApplicationContext(), security, R.layout.list_complex, new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));
}
I have seen example of TreeMap as well,
Map<Integer, List<String>> sortedMap = new TreeMap<Integer, List<String>>(map);
But treemap also gives in ascending order, what I want is in descending order.
best approach to acheive iteration of hashmap in reverse order
HashMap does not define any particular ordering of its element. Therefore the "reverse" order isn't defined either.
For a TreeMap, you can use descendingMap().
Hashmap does not have specific order. But you can use TreeMap.
Perhaps this simple example can help you :
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "abc1");
map.put(2, "abc2");
map.put(3, "abc3");
ArrayList<Integer> keys = new ArrayList<Integer>(map.keySet());
for(int i=keys.size()-1; i>=0;i--){
System.out.println(map.get(keys.get(i)));
}
A HashMap doesn't maintain eny order between keys.
A TreeMap orders its keys by their natural order, or by the order imposed by a comparator that you pass when constructing the map. So if you want to have Integer keys ordered in reverse order, construct the TreeMap this way:
Map<Integer, List<String>> sortedMap =
new TreeMap<Integer, List<String>>(Collections.reverseOrder());
Map<Integer, List<String>> sortedMap = new TreeMap<Integer, List<String>>(Collections.reverseOrder());
Collections.reverseOrder() keeps the map sorted in descending order.
You can use TreeMap#descendingKeySet method.
Map<Integer, List<String>> map = new TreeMap<Integer, List<String>>();
for(Integer key : map.descendingKeySet()) {
List<String> value = map.get(key);
List<Map<String,?>> security = new LinkedList<Map<String,?>>();
for(int ixy = 0; ixy < value.size()-1; ixy++){
security.add(createItem(value.get(ixy), value.get(ixy+1)));
}
adapter.addSection(Integer.toString(key), new SimpleAdapter(getApplicationContext(), security, R.layout.list_complex, new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));
}
Reference:
https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html#descendingKeySet--
You can't iterate over a HashMap in reverse because of this:
This class makes no guarantees as to the order of the map; in
particular, it does not guarantee that the order will remain constant
over time.
What you should use is a LinkedHashMap:
This implementation differs from HashMap in that it maintains a
doubly-linked list running through all of its entries. This linked
list defines the iteration ordering, which is normally the order in
which keys were inserted into the map (insertion-order). Note that
insertion order is not affected if a key is re-inserted into the map.
(A key k is reinserted into a map m if m.put(k, v) is invoked when
m.containsKey(k) would return true immediately prior to the
invocation.)
The hashmap is not an ordered collection. Use TreeMap instead, which has descendingKeySet for reverse iteration. See the javadocs. LinkedHashMap is also a good choice.
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "abc1");
map.put(2, "abc2");
map.put(3, "abc3");
NavigableMap<Integer, String> nmap = map.descendingMap();
for (NavigableMap.Entry<Integer, String> entry : nmap.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
An implementation of NPE idea.
Perhaps you need a NavigableMap, like a TreeMap.
But treemap also gives in asecding order, what i want is in descending order.
Implement a Comparator that will compare it reverse than natural order and then just iterate normally you will have reverse iteration
Use insted:
new TreeMap<>(Collections.reverseOrder())
and you will get what you want.
I've found that the Iterators obtained from Java Hashtable via:
Hashtable.values().iterator() and Hashtable.keys().asIterator()
are both in reverse order by default. One oddity, The values().iterator has a first final value of "0" which I didn't add when populating it.

Sorting HashMaps by value

When I need to sort a HashMap by value, the advice seems to be to create the HashMap and then put the data into a TreeMap which is sorted by value.
For example: Sort a Map<Key, Value> by values (Java)
My question: why is it necessary to do this? Why not create a TreeMap(which is sorted by keys) and then sort it in place by value?
If you know your values to be unique, you can use Guava's BiMap (bidirectional map) to store the data. Create a HashBiMap as you would your HashMap, then create a new TreeMap from its inverse:
new TreeMap<>(biMap.inverse());
That map will then be sorted by the values. Remember that what you're thinking of as "keys" and "values" will be swapped.
If your values are not unique, you can create a multimap of the inverse. A multimap is essentially a mapping from each key to one or more values. It's usually implemented by making a map from a key to a list. You don't have to do that though, because Google did it for you. Just create a multimap from your existing map, and ask Guava to invert it for you into a TreeMultimap, which, as you can guess, is a TreeMap that can hold multiple values per key.
Multimaps.invertFrom(Multimaps.forMap(myMap), new TreeMultimap<V, K>());
Multimap documentation is provided.
Because you can't reorder the entries of a TreeMap manually. TreeMap entries are always sorted on the keys.
I'm going to throw out Map that could be iterated in the order of values as another answer to "How to do it," though...specifically, a solution which doesn't return a map that chokes (by throwing exceptions) on queries to keys not in your original map.
I have this very small code which is working fine:
public class SortMapByValues {
public static void main(String[] args) {
Map<Integer, String> myMap = new LinkedHashMap<Integer, String>();
myMap.put(100, "hundread");
myMap.put(500, "fivehundread");
myMap.put(250, "twofifty");
myMap.put(300, "threehundread");
myMap.put(350, "threefifty");
myMap.put(400, "fourhundread");
myMap = sortMapByValues(myMap);
for (Map.Entry<Integer, String> entry : myMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
public static Map<Integer, String> sortMapByValues(
Map<Integer, String> firstMap) {
Map<String, Integer> SecondyMap = new TreeMap<String, Integer>();
for (Map.Entry<Integer, String> entry : firstMap.entrySet()) {
SecondyMap.put(entry.getValue(), entry.getKey());
}
firstMap.clear();
for (Map.Entry<String, Integer> entry : SecondyMap.entrySet()) {
firstMap.put(entry.getValue(), entry.getKey());
}
return firstMap;
}
}
Output:
500 fivehundread
400 fourhundread
100 hundread
350 threefifty
300 threehundread
250 twofifty
I wrote the following one-liner using Java 8 Stream API to sort any given map by value:
List<Map.Entry<String, String>> sortedEntries = map.entrySet().stream()
.sorted((o1, o2) -> o1.getValue().compareTo(o2.getValue())).collect(Collectors.toList());

sorting treemap based on key, where key is variable

I want to sort the tree map based on the key where key is a variable,so sorting should be based on variable value, How can we achieve this? I want use in built sort method rathar implementing it through code, any reply with example is of great help.
TreeMap (which implements SortedMap) stores automatically the keys in the correct order:
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "one");
map.put(3, "three");
map.put(2, "two");
// prints one two three
for(Integer key : map.keySet()) {
System.out.println(map.get(key));
}
As Key-Type (in that case Integer) you can use any class which implements Comparable (or you can provide a Comparator when creating the TreeMap)
Edit: Okay, here is a suggestion how to re-map your map.
Map<Integer, String> oldMap; // get oldMap from somewhere
// Prepare remapping
Map<Integer, String> newMap = new TreeMap<Integer, String>();
Map<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
// Store a new key for each old key
keyMap.put(oldKey, newKey);
// fill the newMap
for(Integer oldKey : keyMap.keySet()) {
newMap.put(keyMap.get(oldKey), oldMap.get(oldKey));
}
oldMap = newMap; // if needed
A treemap is a Red-black tree, which is a balanced binary search tree. In other words, the tree is already sorted (or rather, arranged as per the binary search tree rules) with its height balanced so that tree operations have a O(lg n) complexity. However, I think what you want is to print all the keys in sorted order. This is as simple as implementing an inorder traversal on the treemap, or you could use the keySet() method to get a Set and iterate over the values.
e.g. of inorder traversal
void inorderTraversal( Node root ){
if( root == null ) return;
inorderTraversal( root.getLeft() );
root.printValue();
inorderTraversal( root.getRight() );
}
EDIT:
Okay, I'm pretty sure this is what you want. You want to sort by values:
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("one", 8);
map.put("two", 10);
map.put("three", 9);
map.put("hundred", 1);
System.out.println(map.values());
Output:
[1, 8, 9, 10]
So this works even for sorting string values:
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(8, "one");
map.put(10, "two");
map.put(9, "three");
map.put(1, "hundred");
System.out.println(map.values());
Output:
[hundred, one, three, two]
Also, sachin take note that having "variable keys" and variable values are completely different things.
TreeMap implements the SortedMap interface and is sorted by its key without you having to do anything:
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.

Categories

Resources