JimmyD
JimmyD

Reputation: 2759

Sort table on multiple Comparator items

I need a way in Java 8 to sort a list of Item objects using on multiple Comparator objects.

The application creates a Comparator on every user action. It's stores the Comparator objects in an ArrayList. It is possible to sort on one Comparator Item but now we need a way to make it possible to sort on multiple Comarator items at the same time.

This line of code I use to sort the list:

tbl.getItems().stream().sorted(groupingComparator);

The variable groupingComparator is from type Comparator<Item>

Now I need to sort on multiple fields that are stored in

ArrayList<Comparator<Item>>

Is this possible in Java 8? And how can I implement this?

Upvotes: 3

Views: 680

Answers (2)

T. Neidhart
T. Neidhart

Reputation: 6200

You can use the thenComparing(Comparator) method available from the Comparator interface to chain multiple Comparators together. See the example below, to create such a chained Comparator from a List using streams.

The domain class we want to use for sorting:

public static class Order {
    String customer;
    String item;

    public Order(String customer, String item)
    {
        this.customer = customer;
        this.item = item;
    }

    public String toString() {
        return "Customer: " + customer + " Item: " + item;
    }
}

Sample code:

public static void main(String... args) throws Throwable
{
    List<Order> orders = new ArrayList<>();
    orders.add(new Order("A", "Item 1"));
    orders.add(new Order("B", "Item 3"));
    orders.add(new Order("A", "Item 2"));
    orders.add(new Order("B", "Item 1"));

    List<Comparator<Order>> comparators =
        Arrays.asList((o1, o2) -> o1.customer.compareTo(o2.customer), // comparator for customer names
                      (o1, o2) -> o1.item.compareTo(o2.item));        // comparator for item names

    Comparator<Order> comp =
        comparators.stream()
                   .reduce(Comparator::thenComparing)
                   // use a default comparator if the comparator list was empty
                   .orElse(Comparator.comparing(Object::toString));

    orders.stream().sorted(comp).forEach((order) ->  System.out.println(order));
}

This snippet will print the Orders sorted first by Customer then by Item name.

Upvotes: 5

JB Nizet
JB Nizet

Reputation: 691953

As simple as that:

public class CompositeComparator implements Comparator<Item> {
    private List<Comparator<Item>> comparators;

    public CompositeComparator(List<Comparator<Item>> comparators) {
        this.comparators = comparators;
    }

    @Override
    public int compare(Item o1, Item o2) {
        int result = 0;
        for (Comparator<Item> c : comparators) {
            result = c.compare(o1, o2);
            if (result != 0) {
                break;
            }
        }
        return result;
    }
}

Upvotes: 2

Related Questions