Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort collection by two different properties

I have a class with multiple properties I want it sorted by. Currently I am sorting by Name like this:

Collections.sort(rowItems, new Comparator() {

    public int compare(Object o1, Object o2) {
        SearchRowItem p1 = (SearchRowItem) o1;
        SearchRowItem p2 = (SearchRowItem) o2;
        return p1.getName().compareToIgnoreCase(p2.getName());
    }

});

But I also want to sort by LastName secondarily to Name (so if names are the same sort by LastName second). How do I combine my code below with my first sort to get the outcome I described?

Collections.sort(rowItems, new Comparator() {

    public int compare(Object o1, Object o2) {
        SearchRowItem p1 = (SearchRowItem) o1;
        SearchRowItem p2 = (SearchRowItem) o2;
        return p1.getLastName().compareToIgnoreCase(p2.getLastName());
    }

});
like image 751
BluGeni Avatar asked Dec 11 '22 01:12

BluGeni


2 Answers

A simple Comparator that first compares the name and then the lastName will work with the Collections.sort method.

From the JavaDoc:

Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.


So, here is the example of the Comparator that compares on two properties:

Collections.sort(rowItems, new Comparator<SearchRowItem>() {
    @Override
    public int compare(final SearchRowItem o1, final SearchRowItem o2) {
        int compare = o1.getName().compareToIgnoreCase(o2.getName());
        if (compare != 0) {
            return compare;
        }
        return o1.getLastName().compareToIgnoreCase(o2.getLastName());
    }
});

However, there are other alternatives. Java 8 introduced streams where sorting integrates nicely. Together with the new methods Comparator.comparing and the thenCompare a nice stream can be created like this.

final List<SearchRowItem> collect = rowItems.stream()
        .sorted(
                Comparator.comparing(SearchRowItem::getName, String::compareToIgnoreCase)
                          .thenComparing(SearchRowItem::getLastName, String::compareToIgnoreCase))
        .collect(Collectors.toList());

Note that the latter does not sort the original List but creates a new sorted list.

like image 129
wassgren Avatar answered Dec 28 '22 07:12

wassgren


If getName() returns 0 it means that both objects have the same name - only then should you use getLastName():

Collections.sort(rowItems, new Comparator() {

    @Override
    public int compare(Object o1, Object o2) {
        SearchRowItem p1 = (SearchRowItem) o1;
        SearchRowItem p2 = (SearchRowItem) o2;
        int nameComp =  p1.getName().compareToIgnoreCase(p2.getName());
        if (nameComp != 0) {
            return nameComp;
        }
        return p1.getLastName().compareToIgnoreCase(p2.getLastName());
    }
});

EDIT:
The answer above follows the OP's style. However, if possible, you should use generics to clean up the code:

Collections.sort(rowItems, new Comparator<SearchRowItem>() {

    @Override
    public int compare(SearchRowItem p1, SearchRowItem p2) {
        int nameComp =  p1.getName().compareToIgnoreCase(p2.getName());
        if (nameComp != 0) {
            return nameComp;
        }
        return p1.getLastName().compareToIgnoreCase(p2.getLastName());
    }
});
like image 41
Mureinik Avatar answered Dec 28 '22 07:12

Mureinik