Collectors.groupingBy() returns result sorted in ascending order java
Asked Answered
G

6

7

I am sending result in descending order but I get output with ascending order

List<myEntity> myData = new ArrayList<>();
Map<Integer,List<myEntity>> myid = new LinkedHashMap<>();

try {
    myData = myService.getData(id); 
    myid = myData.stream().collect(Collectors.groupingBy(myEntity::getDataId)); 

Here mydata is sorted by desc order but after creating collections by group data id my list get sorted with ascending order. I want my collection list to be descending order not ascending order.

Gonzalez answered 5/9, 2018 at 19:20 Comment(7)
Just reverse the list first.Moulmein
can you give me example ?Gonzalez
Collections.reverse(myData);Moulmein
It is not working for me..I am getting data in ascending order only ..i want my collection to be sorted in decsending orderGonzalez
Which part is not sorted? The myid map, or the myEntity inside the list?Adamic
Maybe try Collectors.groupingBy(myEntity::getDataId, LinkedHashMap::new, Collectors.toList())Adamic
@Adamic You should post that comment as an answer, I think it's the correct solution to the problemAffiche
M
17

As @Holger described in Java 8 is not maintaining the order while grouping , Collectors.groupingBy() returns a HashMap, which does not guarantee order.

Here is what you can do:

myid = myData.stream()
.collect(Collectors.groupingBy(MyEntity::getDataId,LinkedHashMap::new, toList()));

Would return a LinkedHashMap<Integer, List<MyEntity>>. The order will also be maintained as the list used by collector is ArrayList.

Myrtismyrtle answered 5/9, 2018 at 20:28 Comment(5)
@FedericoPeraltaSchaffner oh ! my bad , sorry i missed the point , i'll update the answer, tnx for sayingMyrtismyrtle
That’s still missing the point. You are sorting the lists, which do maintain the encounter order, without solving the actual problem of the map not maintaining the order.Featherstitch
Thank you for solution I used above code it is giving me my collection with reverse order but after sending data to UI side it is again showing in ascending order dont know what is wrong i am using return ResponseEntity.ok(myidcollection);..can you please help me with thisGonzalez
@Gonzalez I'm not a moderator, but it is my understanding that according to the rules of this site, you should ask a separate question asking that, linking to this question and answer. The problem might be that in the UI side they're using a HashMap instead of a LinkedHashMap, or who knows what... We need more context, this is why I'm asking you to ask a separate question.Affiche
Thank you I will ask new questionGonzalez
E
9

Collectors.groupingBy returns a HashMap without any order as such (as to why you see "some order" is explained here). The correct way to do this is to specify the Map that preserve the order inside the Collectors.groupingBy:

myData.stream()
      .collect(Collectors.groupingBy(
          MyEntity::getDataId,
          LinkedHashMap::new,
          Collectors.toList()     

))
Entrench answered 6/9, 2018 at 8:9 Comment(0)
C
4

collect(Collectors.groupingBy()) returns a new Map which overwrites the variable to your previous LinkedHashMap. Your initial assignment is therefore futile. The exact type returned is undefined by the specs but in my test run it returned a HashMap. (Never assume this will always be the case across different versions and brands of Java!)

But the main issue is that you're storing Integer as keys. If the values of those keys is smaller than the modulus of the table inside the HashMap, they will just appear ordered (because the hashCode of an Integer is just it;s value). When I tested with 1000 Integer values of 0..999, the hashtable (the array as part of the inner workings of HashMap) appeared to be of size 2048. (Again, undocumented so don't assume it!)

In summary, the reason you see the results in ascending order is because of an implementation artifact, not because there's a specific reason.

Caulescent answered 5/9, 2018 at 20:19 Comment(0)
B
0

You need reverse order of map. So In java 8 , i solved with this.

myData = myService.getData(id);
myid = myData.stream().collect(Collectors.groupingBy(myEntity::getDataId));

Map<Integer, List<myEntity>> finalMap = new LinkedHashMap<>();
myid.entrySet().stream()
        .sorted(Map.Entry.<Integer, List<myEntity>>comparingByKey()
                .reversed())
        .forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
System.out.println("FINAL RESULT : " + finalMap);

Entryset gives us Integers of this map of myid. So sort and get from first map which is myid and put in finalMap

Bohun answered 5/9, 2018 at 20:30 Comment(6)
order of which list ? But he said now ascending order but he wants descending order. I solved this situtationBohun
How can i know service's return , he can sort i think or provide sorted ? i wrote this code according to questions. And I sort this keyset and map. It does work correctly, can u try? i tried with lots of oddsBohun
In the question, OP says textually Here mydata is sorted by desc order, so the list mydata is already sorted in desc order. The problem is that after grouping, the map is not sorted any more. This is because the map is a HashMap instead of a LinkedHashMap, which preserves insertion order.Affiche
.sorted(Map.Entry.<Integer, List<myEntity>>comparingByKey() .reversed()) this line provide us sortingBohun
Thank you for solution ...I used above code and I am getting in descending order.. but dont know in UI side its showing in ascending order only I m using ResponseEntity to send mydata .... so Can you please help with this ? Thank you againGonzalez
Backend never knows frontend. U can send any order. if ui wants to show in asc order, it can sort in js side or whatelse. Backend should ignore this sorting in shortly.Bohun
S
0

There is an example in Collectors groupingby method javadoc. which u can use TreeMap to sort the result.

 Map<City, Set<String>> namesByCity
 *   = people.stream().collect(
 *     groupingBy(Person::getCity,
 *                TreeMap::new,
 *                mapping(Person::getLastName,
 *                        toSet())));

so i think u can try this following code.

myid = myData.stream().collect(Collectors.groupingBy(MyEntity::getDataId,TreeMap::new, toList()));
Saltire answered 6/5 at 6:37 Comment(0)
L
0
 Map<String, List<TargetVaRResponsePTF>> statusMap = ptfDetails.stream().collect(Collectors.groupingBy(item -> {
      if (item.getStatus().equalsIgnoreCase("closed") && !item.isHasError()) {
        return "Completed";
      } else if (item.getStatus().equalsIgnoreCase("closed") && item.isHasError()) {
        return "CompletedWithError";
      } else if (item.getStatus().equalsIgnoreCase("running")) {
        return "Running";
      } else if (item.getStatus().equalsIgnoreCase("waiting")) {
        return "Waiting";
      } else if (item.getStatus().equalsIgnoreCase("error")) {
        return "Error";
      }
      System.out.println("none");
      return "none";
    }, ConcurrentHashMap::new, Collectors.toList()));
Lebrun answered 14/5 at 12:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.