1

I have the following:

List someObjectList (one variable inside is years already ordered as DESC by PosgreSQL)

Let us say from 2018 to 2016 years (I need it as set because many someObject contains the same years value and I need just the unique in DESC order

I put it in Stream as follows:

Set<Integer> yearsSet = someObjectList.stream()
   .map(SomeObject::getYears)
   .collect(Collectors.toSet())

It returns set but with ASC years like 2016, 2017, 2018 not as had in objectsList ([0].getYears()>2018, [1].getYears()> 2017...etc) at the beginning

Also I used following .sort() method in both ways:

someObjectList.stream().map(SomeObject::getYears)
           .sorted(Comparator.comparing(Integer::intValue).reversed())
           .collect(Collectors.toSet())

and

someObjectList.stream().map(SomeObject::getYears)
            .sorted(Comparator.comparing(Integer::intValue))
            .collect(Collectors.toSet())

Both did nothing (maybe I used Integer::intValue incorrectly)?

Then I came to a solution which is ugly (here I get list but it is okey as no dublicated are received):

someObjectList.stream().map(SomeObject::getYears)
            .collect(Collectors.toSet())
            .stream().sorted(Comparator.comparing(Integer::intValue).reversed())
            .collect(Collectors.toList())

It does the job but it is ugly. Any advise where I am doing wrong or how could I replace this "sausage" part?

I read somewhere that Maps can not be easily sorder and maybe it is applied to sets?

Thank you for your time and advise

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Bronius Janonis
  • 75
  • 2
  • 12
  • 1
    `List ...= ... .toSet()` sure ? – azro May 03 '18 at 12:55
  • Yes, corrected. Originally in code it does not throw any mistyping exceptions. – Bronius Janonis May 03 '18 at 13:03
  • What you have is a `List` where `POJO` have a field `year` and you want to extract a distinct list of year sorted ? Correct ? This is not really clear. Provide a [mcve] with the `TimeVerification` class – AxelH May 03 '18 at 13:04
  • Yes, you are correct. Also I have chosen Set because I need just unique years descended. I know there are other ways but I picked Set. Unfortunately I can provide just that and it is my first post so thank you for patience. Corrected the Object so the code should represent the problem in most accurate way. – Bronius Janonis May 03 '18 at 13:06
  • 2
    Don't forget to check [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers). You can accept the answer that help you the most or that fit the most your question (only one). Accepting an answer will "mark" the question as answered. – AxelH May 03 '18 at 13:47

4 Answers4

3

As @axelh did mention, you can not order a set (unless you opt for a TreeSet as an implementation), so here is a solution using TreeSet and providing the comparator in question as the constructor's parameter :

final Set<Integer> yearsSet = someObjectList.stream()
    .map(SomeObject::getYears)
    .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.reverseOrder())));
marsouf
  • 1,107
  • 8
  • 15
  • I have to admit I am not really good with the `collect` method yet... didn't even though about providing an instance of a sorted set... – AxelH May 03 '18 at 13:34
  • Noted. Sets can not be ordered thus the options are either to remove the dublicates and sort as list (porvided by AlexH) or as you wrote to create in Collector sortable TreeSet. Thank you! – Bronius Janonis May 03 '18 at 13:37
  • 1
    `TreeSet` is not the only option. You can use a `LinkedHashSet` which maintains the insertion order, hence `.sorted(Comparator.comparing(Integer::intValue)) .collect(Collectors.toCollection(LinkedHashSet::new))` will return a set reflecting the pre-sorted order (but doesn’t have to stay sorted when subsequently modified). – Holger May 03 '18 at 16:31
  • @Holger yes definitely, if the resulting `Set` is not going to be modified afterwards, the `LinkedHashSet` is one way to go for. – marsouf May 04 '18 at 10:08
2

You can't guarantees the order with a Set (only some implementation do it like SortedSet), see Java Set retain order? to find more information.

And the Collectors.toSet even mention it :

This is an unordered Collector.

You can simply use a List in that case. Using Stream.distinct to remove duplicates.

List<TimeVerification> list = new ArrayList<>();
list.add(new TimeVerification(2016));
list.add(new TimeVerification(2017));
list.add(new TimeVerification(2019));
list.add(new TimeVerification(2016));
list.add(new TimeVerification(2018));
list.add(new TimeVerification(2015));

List<Integer> orderedList = list.stream()
    .map(TimeVerification::getYear)
    .distinct()
    .sorted(Comparator.reverseOrder())
    .collect(Collectors.toList());

System.out.println(orderedList);

[2019, 2018, 2017, 2016, 2015]

Or use other Set to collect the Stream (see marsouf's answer about that).

Example used with :

public class TimeVerification {
    int year;

    public TimeVerification(int year) {
        this.year = year;
    }

    public int getYear() {
        return year;
    }
}
AxelH
  • 14,325
  • 2
  • 25
  • 55
1

I might be wrong but it looks like you want to create a sorted set from the list of someObjects. One of the possible way is to collect to TreeSet with a custom comparator:

Set<Integer> years = someObjectList.stream()
   .map(SomeObject::getYears)
   .collect(Collectors.toCollection(() -> new TreeSet<Integer>()));

I assume that SomeObject::getYears returns an Integer.

if you need years in descent order add Comparator.reverseOrder() to the TreeSet constructor

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
0

The problem you are facing is that Collectors.toSet() will create a HashSet. So the ordering will depend on the hashCode() value of Integer. When you use Collectors.toList() the order will be based on insert order.

TomVW
  • 1,510
  • 13
  • 26