Marcel
Marcel

Reputation: 51

Sort a List using a comparator with multiple criteria. FIFO

I have a problem with sorting the list, I did all of the tasks which are in a given exercise, but it doesn't quite make sense to me and I want to fix it. So I have a List of people who are waiting in the queue in, let's say, a pharmacy. People who are pregnant should have priority above everyone, the next priority has people with age >60. Everything works fine, except the fact the person with age >60 which came first is behind the people with age >60 who came later (I just need it to work with a FIFO rule, with the pregnant criteria it works as expected).

I sorted the list first with the compareTo() method and then with the external comparator class I created.

public class Main {
    public static void main(String[] args) {

        List<Customer> pharmacyQueue = new ArrayList<>();
        CustomerComparator customerComparator = new CustomerComparator();

        pharmacyQueue.add(new Customer(25, false, "Przemek"));
        pharmacyQueue.add(new Customer(35, true, "Anita"));
        pharmacyQueue.add(new Customer(55, false, "Wiesława"));
        pharmacyQueue.add(new Customer(25, true, "Maryja"));
        pharmacyQueue.add(new Customer(85, false, "Halinka"));
        pharmacyQueue.add(new Customer(55, false, "Stasia"));
        pharmacyQueue.add(new Customer(20, true, "Marta"));
        pharmacyQueue.add(new Customer(65, false, "Bożenka"));
        pharmacyQueue.add(new Customer(75, false, "Paoasdo"));

        Collections.sort(pharmacyQueue); 
        Collections.sort(pharmacyQueue, customerComparator);

        System.out.println("Sorted queue: ");
        for (Customer c : pharmacyQueue){
            System.out.println(c);
        }

    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor

public class Customer implements Comparable<Customer> {
    private int age;
    private boolean isPregnant;
    private String name;

    public int compareTo(Customer o) {
        if (this.age > 60){
            return -1;
        }else if (this.age < 60){
            return 1;
        }
        return 0;
    }
public class CustomerComparator implements Comparator<Customer> {
    @Override
    public int compare(Customer o1, Customer o2) {


        if (o1.isPregnant() && !o2.isPregnant()){
            return -1;
        }
        if (o1.isPregnant() && o2.isPregnant()){
            return 1;
        }


        return 0;
    }
}

The result:

Sorted queue: 
Customer(age=35, isPregnant=true, name=Anita) //fine
Customer(age=25, isPregnant=true, name=Maryja) //fine
Customer(age=20, isPregnant=true, name=Marta) //fine
Customer(age=75, isPregnant=false, name=Paoasdo) //should be 6th
Customer(age=65, isPregnant=false, name=Bożenka) //should be 5th
Customer(age=85, isPregnant=false, name=Halinka) //should be 4th
Customer(age=25, isPregnant=false, name=Przemek) //fine
Customer(age=55, isPregnant=false, name=Wiesława) //fine
Customer(age=55, isPregnant=false, name=Stasia) //fine

Upvotes: 1

Views: 358

Answers (2)

Jiri Tousek
Jiri Tousek

Reputation: 12440

For that, you essentially need two things:

  1. A stable sort algorithm, i.e. an algorithm that won't disturb order of "equal" (in terms of sort order) elements
  2. A comparator that correctly identifies what elements are "equal"
    • That's where both your comparators fail - the age comparator doesn't even ever use info about the other object (!!!), and the pregnancy comparator has a bug that considers two pregnant customers to have a different priority.

Upvotes: 2

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

As pointing out in the comments, sorting the list twice does the same thing as sorting with the second ordering only (only slower). Oh, and many sorts such as QuickSort are unstable (rearrange tied values), whilst other such as MergeSort are stable.

You want to combine the comparators (or comparator and comparable). Fortunately (since 1.8) this is really easy with these two methods in java.util.Comparator

static <T extends Comparable<? super T>> Comparator<T> naturalOrder()

default Comparator<T> thenComparing​(Comparator<? super T> other)

Getting those the right way around is left as an exercise.

Upvotes: 0

Related Questions