Bartek
Bartek

Reputation: 137

How to compare integers in order, but with zero last

I have list like this:

List<Integer> list = new ArrayList<>();
list.add(24);
list.add(12);
list.add(0);
list.add(36);
list.add(1);
list.add(99);

I want to sort it ascending, but 0 has to always be the last element. Is there any way to simplify it?

List<Integer> collect = list.stream()
         .sorted((a,b) -> b.compareTo(a))
         .sorted((a, b) -> Integer.valueOf(0).equals(a) ? 1 : -1)
         .collect(Collectors.toList());

Upvotes: 1

Views: 123

Answers (4)

M. Justin
M. Justin

Reputation: 21255

I would create a custom Comparator that sorts the elements in the desired order, then pass that to Stream.sorted:

Comparator<Integer> comparator = Comparator
        .comparing((Integer i) -> i == 0 ? 1 : 0)
        .thenComparing(Comparator.naturalOrder());

List<Integer> collect = list.stream().sorted(comparator).toList();

Comparator.comparing((Integer i) -> i == 0 ? 1 : 0) treats 0 as greater than every other Integer, and all other values as equal. The call to .thenComparing then performs a tie-breaker comparison using the standard integer comparison in the case where the first comparison resulted in 0 (i.e. neither value was 0, or both values were 0).

Incidentally, having the Comparator means that the list can be easily sorted in-place if you want to mutate it, rather than creating a copy using streams:

List<Integer> list = new ArrayList<>(List.of(24, 12, 0, 36, 1, 99));
list.sort(comparator);

Upvotes: 0

Eritrean
Eritrean

Reputation: 16498

May be introducing variables for the comparators and comparing the boolean if an int equals to zero might simplify or at least make it readable

Comparator<Integer> natural  = Comparator.naturalOrder();
Comparator<Integer> zeroLast = Comparator.comparing(i -> i.equals(0));

List<Integer> collect = list.stream()
                            .sorted(natural)
                            .sorted(zeroLast)
                            .collect(Collectors.toList());

Upvotes: 0

zysaaa
zysaaa

Reputation: 1877

You can process in the same sorted:

List<Integer> collect = list.stream()
                        .sorted((o1, o2) -> o1 == 0 ? 1 : (o2 == 0 ? -1 : o1.compareTo(o2)))
                        .collect(Collectors.toList());

Upvotes: 0

rzwitserloot
rzwitserloot

Reputation: 103273

List<Integer> list = List.of(24, 12, 0, 36, 1, 99);
List<Integer> sorted = list.stream()
.sorted(Comparator.comparingInt(a -> a == 0 ? Integer.MAX_VALUE : a))
.toList();
System.out.println(sorted);

Seems to work; prints [1, 12, 24, 36, 99, 0].

The one downside is that it won't do the right thing if literally the maximum integer value (which is 2147483647) is in your list, in which case it'll sort the 0s amongst them instead of after them. If that is a problem, nothing is going to look significantly shorter than what you did.

NB: Your code appears to sort descending. In which case the 0 would already sort at the end unless you have negative numbers. If that's what you want and 'ascending' was a typo, you'd have to use MIN_VALUE instead, and reverse the comparator (tack .reverse() t the end).

Upvotes: 2

Related Questions