Alexandre QUERE
Alexandre QUERE

Reputation: 33

Unexpected sorted list

Greeting,

I have 2 objects :

I wrote this code:

public List<Petition> getTheMostSigned(long groupId){

    List<Petition> petitionList = petitionPersistence.findByStatusAndGroupId(0,groupId);

    _log.info("list avant getTheMostSigned size  : "+petitionList.stream().map(petition -> petition.getSignataires().size()).collect(Collectors.toList()));

    List<Petition> resultList = petitionList.stream()
            .sorted(Comparator.comparingInt(petition -> petition.getSignataires().size()))
            .sorted(Collections.reverseOrder())
            .collect(Collectors.toList());

    _log.info("list apres getTheMostSigned size  : "+resultList.stream().map(petition -> petition.getSignataires().size()).collect(Collectors.toList()));

    return resultList;

The getSignataires() return a List.

but the result wasn't what I expected :

enter image description here

2018-09-12 12:44:25.686 INFO  [http-nio-8080-exec-10][PetitionLocalServiceImpl:390] list avant getTheMostSigned size  : [0, 0, 400, 0, 3, 401, 5501]
2018-09-12 12:44:25.856 INFO  [http-nio-8080-exec-10][PetitionLocalServiceImpl:396] list apres getTheMostSigned size  : [5501, 401, 3, 0, 0, **400**, 0]

As you can see, the penultimate is not the good one. do you know why the Comparator isn't doing the job ?

Upvotes: 3

Views: 112

Answers (3)

davidxxx
davidxxx

Reputation: 131526

The result is expected as you chain two sorts.
The first one (.sorted(Comparator.comparingInt(petition -> petition.getSignataires().size())) sorts by the list field size). Then the second one (.sorted(Collections.reverseOrder())) overwrites the first sort result as the last one sorts according to the reverse natural order of Petition.
As you invoke the sort stream operation twice, broadly it is like if you had used this logical :

List<Petition> petitionList = ...;
// first sort
petitionList.sort(Comparator.comparingInt(petition -> petition.getSignataires().size());
// second sort
petitionList.sort(Collections.reversed());

What you need is defining a Comparator instance that combines these constraints.
And from Java 8, you can create Comparators and combine them thanks essentially to .thenComparingXXX() and .reversed() methods.

So you could do :

.sorted(Comparator.comparingInt(petition -> petition.getSignataires().size())
                  .reversed()
       )

Upvotes: 5

Oomph Fortuity
Oomph Fortuity

Reputation: 6178

Below is another way to do thing using Collection's other overloaded method which uses custom compactor

Comparator<Petition> cmp = 
         (Petition left, Petition right) -> 
              left.getSignataires().size() - right.getSignataires().size();

List<Petition> resultList = petitionList.stream()
        .sorted(Collections.reverseOrder(cmp))
        .collect(Collectors.toList());

Upvotes: 1

Andrew
Andrew

Reputation: 49656

You don't need two sorted operations. They won't be combined to produce a resulting Comparator.

The first constructs a Comparator<Integer> for int size() values, while the second ignores the previous call and applies its own Comparator<Petition> (Comparator.<Petition>reverseOrder()).

Comparator<Petition> reversedSignaturesSizeComparator 
        = Comparator.<Petition>comparingInt(p -> p.getSignataires().size()).reversed();
List<Petition> resultList = petitionList.stream()
                                        .sorted(reversedSignaturesSizeComparator)
                                        .collect(Collectors.toList());

Upvotes: 3

Related Questions