Reputation: 523
I want to sort LinkedHashMap that has LinkedList<Integer>
as key and float[]
as value.
For example let's say I have such LinkedHashMap like this:
LinkedHashMap<LinkedList<Integer>, float[]> hm = new LinkedHashMap<>();
LinkedList<Integer> linkedlist;
linkedlist = new LinkedList<>();
linkedlist.add(10);
linkedlist.add(7);
hm.put(linkedlist, new float[]{0.14f, 1.2f, 85.01f});
linkedlist = new LinkedList<>();
linkedlist.add(0);
linkedlist.add(41);
hm.put(linkedlist, new float[]{10.3f, 50.05f, 9.9f});
linkedlist = new LinkedList<>();
linkedlist.add(210);
linkedlist.add(3);
hm.put(linkedlist, new float[]{17.0f, 4.0f, 2.1f});
Now what I want is the output to be:
{0, 41}, {10.3f, 50.05f, 9.9f}
{10, 7}, {0.14f, 1.2f, 85.01f}
{210, 3}, {17.0f, 4.0f, 2.1f}
But when I use suggested solution (suggested by some of you in the comments section saying it is duplicate of another post that already have the right answer - the one below, link to it here) where it created new LinkedHashMap (cos I do not know how to sort the original LinkedHashMap in place by this code, unfortunately) like this:
LinkedHashMap<LinkedList<Integer>, float[]> sortedMap = new LinkedHashMap<>();
hm.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));
hm = sortedMap;
My NetBeans 8.0.2 show me error about the line .sorted(Map.Entry.comparingByKey())
saying:
incompatible types: inference variable K has incompatible bounds
equality constraints: LinkedList<Integer>
upper bounds: Comparable <? super K>
where K,V are type-variables:
K extends Comparable<? super K> declared in method <K,V>comparingByKey()
V extends Object declared in method <K,V>comparingByKey()
I thought maybe for some reason the values in the LinkedList are wrong so I tested it like this and it shows those are all correct (I tested just first 50 entries as the list have hundreds of them):
for (int i = 0; i < hm.size(); i++) {
if (i < 50) {
for (Map.Entry<LinkedList<Integer>, float[]> entry : hm.entrySet()) {
LinkedList<Integer> k = entry.getKey();
System.out.println(k);
}
}
}
Upvotes: 1
Views: 453
Reputation: 86272
The simple fix: You said that you wanted sorting by the first (0th) element of the list. So specify that:
hm.entrySet()
.stream()
.sorted(Comparator.comparing(me -> me.getKey().get(0)))
.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));
With this sorting let’s try writing out the sorted map afterwards, for example:
sortedMap.forEach((k, v) -> System.out.println("" + k + " -> " + Arrays.toString(v)));
[0, 41] -> [10.3, 50.05, 9.9] [10, 7] -> [0.14, 1.2, 85.01] [210, 3] -> [17.0, 4.0, 2.1]
If you didn’t want to create a new map, you must remove each key before inserting it again for the order to be changed:
hm.entrySet()
.stream()
.sorted(Comparator.comparing(me -> me.getKey().get(0)))
.forEachOrdered(x -> {
hm.remove(x.getKey());
hm.put(x.getKey(), x.getValue());
});
hm.forEach((k, v) -> System.out.println("" + k + " -> " + Arrays.toString(v)));
Now the output is the same as above.
Upvotes: 1
Reputation: 311188
The problem with this approach is that the key you have, a LinekdList<Integer>
is not Comparable
. You can overcome this by providing a custom Comparator
.
A common way to implement such comparators is to compare the integers in matching places, until you hit a pair that aren't equal. If one of the lists is shorter than the other and you didn't hit a non-matching element in it before its end, you can define it as "smaller" than the longer list:
Comparator<LinkedList<Integer>> cmp = new Comparator<LinkedList<Integer>>() {
@Override
public int compare(LinkedList<Integer> o1, LinkedList<Integer> o2) {
Iterator<Integer> i1 = o1.iterator();
Iterator<Integer> i2 = o2.iterator();
// Iterate over the first list
while (i1.hasNext()) {
Integer x1 = i1.next();
// If the second list has no more elements, it's "smaller"
if (!i2.hasNext()) {
return 1;
}
Integer x2 = i2.next();
int cmp = Integer.compare(x1, x2);
if (cmp != 0) {
// If the matching items aren't equal, we know which list is "smaller"
return cmp;
}
}
// Done going over the first list.
// If the second one still has items, it's "bigger"
if (i2.hasNext()) {
return -1;
}
// If not, both lists are equal
return 0;
}
};
Once you have that comparator available, you just need to use it for sorting the map's keys:
LinkedHashMap<LinkedList<Integer>, float[]> sortedMap = new LinkedHashMap<>();
hm.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey(cmp)) // Here
.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));
hm = sortedMap;
Upvotes: 1