How do I use Comparator to define a custom sort order?

JavaSortingEnums

Java Problem Overview


I want to develop a sorting demo for car list. I am using data table to display car list. Now actually I want to sort the list by car color. Here it is not sort by alphabetic order. I want to use my custom sorting order like Red car come first, then Blue, etc.

For that I try to use Java Comparator and Comparable but it allows to sort in alphabetic order only.

So, can any one guide me the way to implement the technique to use so that the sorting becomes faster.

class Car implements Comparable<Car>
{
    private String name;
    private String color;

    public Car(String name, String color){
        this.name = name;
        this.color = color;
    }

    //Implement the natural order for this class
    public int compareTo(Car c) {
        return name.compareTo(c.name);
    }

    static class ColorComparator implements Comparator<Car> {
        public int compare(Car c1, Car c2) {
            String a1 = c1.color;
            String a2 = c2.color;
            return a1.compareTo(a2);
        }
    }

    public static void main(String[] args) {
        List<Car> carList = new ArrayList<>();
        List<String> sortOrder = new ArrayList<>();

        carList.add(new Car("Ford","Silver"));
        carList.add(new Car("Tes","Blue"));
        carList.add(new Car("Honda","Magenta"));

        sortOrder.add("Silver");
        sortOrder.add("Magenta");
        sortOrder.add("Blue");
        
        // Now here I am confuse how to implement my custom sort        	 
    }
}

Java Solutions


Solution 1 - Java

I recommend you create an enum for your car colours instead of using Strings and the natural ordering of the enum will be the order in which you declare the constants.

public enum PaintColors {
    SILVER, BLUE, MAGENTA, RED
}

and

 static class ColorComparator implements Comparator<CarSort>
 {
     public int compare(CarSort c1, CarSort c2)
     {
         return c1.getColor().compareTo(c2.getColor());
     }
 }

You change the String to PaintColor and then in main your car list becomes:

carList.add(new CarSort("Ford Figo",PaintColor.SILVER));

...

Collections.sort(carList, new ColorComparator());

Solution 2 - Java

How about this:

List<String> definedOrder = // define your custom order
    Arrays.asList("Red", "Green", "Magenta", "Silver");

Comparator<Car> comparator = new Comparator<Car>(){

    @Override
    public int compare(final Car o1, final Car o2){
        // let your comparator look up your car's color in the custom order
        return Integer.valueOf(
            definedOrder.indexOf(o1.getColor()))
            .compareTo(
                Integer.valueOf(
                    definedOrder.indexOf(o2.getColor())));
    }
};

In principle, I agree that using an enum is an even better approach, but this version is more flexible as it lets you define different sort orders.

Update

Guava has this functionality baked into its Ordering class:

List<String> colorOrder = ImmutableList.of("red","green","blue","yellow");
final Ordering<String> colorOrdering = Ordering.explicit(colorOrder);
Comparator<Car> comp = new Comparator<Car>() {
    @Override
    public int compare(Car o1, Car o2) {
        return colorOrdering.compare(o1.getColor(),o2.getColor());
    }
}; 

This version is a bit less verbose.


Update again

Java 8 makes the Comparator even less verbose:

Comparator<Car> carComparator = Comparator.comparing(
        c -> definedOrder.indexOf(c.getColor()));

Solution 3 - Java

Comparator in line ...

List<Object> objList = findObj(name);
Collections.sort(objList, new Comparator<Object>() {
	@Override
	public int compare(Object a1, Object a2) {
		return a1.getType().compareToIgnoreCase(a2.getType());
	}
});

Solution 4 - Java

I think this can be done as follows:

class ColorComparator implements Comparator<CarSort>
{
    private List<String> sortOrder;
    public ColorComparator (List<String> sortOrder){
        this.sortOrder = sortOrder;
    }

    public int compare(CarSort c1, CarSort c2)
    {
        String a1 = c1.getColor();
        String a2 = c2.getColor();
        return sortOrder.indexOf(a1) - sortOrder.indexOf(a2);
     }
 }

For sorting use this:

Collections.sort(carList, new ColorComparator(sortOrder));

Solution 5 - Java

I had to do something similar to Sean and ilalex's answer.
But I had too many options to explicitly define the sort order for and only needed to float certain entries to the front of the list ... in the specified (non-natural) order.
Hopefully this is helpful to someone else.

public class CarComparator implements Comparator<Car> {

	//sort these items in this order to the front of the list 
	private static List<String> ORDER = Arrays.asList("dd", "aa", "cc", "bb");

	public int compare(final Car o1, final Car o2) {
		int result = 0;
		int o1Index = ORDER.indexOf(o1.getName());
		int o2Index = ORDER.indexOf(o2.getName());
		//if neither are found in the order list, then do natural sort
		//if only one is found in the order list, float it above the other
		//if both are found in the order list, then do the index compare
		if (o1Index < 0 && o2Index < 0) result = o1.getName().compareTo(o2.getName());
		else if (o1Index < 0) result = 1;
		else if (o2Index < 0) result = -1;
		else result = o1Index - o2Index;
		return result;
	}

//Testing output: dd,aa,aa,cc,bb,bb,bb,a,aaa,ac,ac,ba,bd,ca,cb,cb,cd,da,db,dc,zz
}

Solution 6 - Java

I will do something like this:

List<String> order = List.of("Red", "Green", "Magenta", "Silver");

Comparator.comparing(Car::getColor(), Comparator.comparingInt(c -> order.indexOf(c)))

All credits go to @Sean Patrick Floyd :)

Solution 7 - Java

In Java 8 you can do something like this:

You first need an Enum:

public enum Color {
    BLUE, YELLOW, RED
}

Car class:

public class Car {

    Color color;

    ....

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}

And then, using your car list, you can simply do:

Collections.sort(carList, Comparator:comparing(CarSort::getColor));

Solution 8 - Java

Define one Enum Type as

public enum Colors {
	 BLUE, SILVER, MAGENTA, RED
}

Change data type of color from String to Colors Change return type and argument type of getter and setter method of color to Colors

Define comparator type as follows

static class ColorComparator implements Comparator<CarSort>
{
    public int compare(CarSort c1, CarSort c2)
    {
        return c1.getColor().compareTo(c2.getColor());
    }
}

after adding elements to List, call sort method of Collection by passing list and comparator objects as arguments

i.e, Collections.sort(carList, new ColorComparator()); then print using ListIterator.

full class implementation is as follows:

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;    
import java.util.ListIterator;

public class CarSort implements Comparable<CarSort>{

    String name;
    Colors color;

    public CarSort(String name, Colors color){
        this.name = name;
        this.color = color;
    } 

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Colors getColor() {
        return color;
    }
    public void setColor(Colors color) {
        this.color = color;
    }

    //Implement the natural order for this class
    public int compareTo(CarSort c)
    {
        return getName().compareTo(c.getName());
    }

    static class ColorComparator implements Comparator<CarSort>
    {
        public int compare(CarSort c1, CarSort c2)
        {
            return c1.getColor().compareTo(c2.getColor());
        }
    }
    
    public enum Colors {
    	 BLUE, SILVER, MAGENTA, RED
    }

     public static void main(String[] args)
     {
         List<CarSort> carList = new ArrayList<CarSort>();
         List<String> sortOrder = new ArrayList<String>();

         carList.add(new CarSort("Ford Figo",Colors.SILVER));
         carList.add(new CarSort("Santro",Colors.BLUE));
         carList.add(new CarSort("Honda Jazz",Colors.MAGENTA));
         carList.add(new CarSort("Indigo V2",Colors.RED));
         Collections.sort(carList, new ColorComparator());
         
         ListIterator<CarSort> itr=carList.listIterator();
         while (itr.hasNext()) {
			CarSort carSort = (CarSort) itr.next();
			System.out.println("Car colors: "+carSort.getColor());
		}
     }
}

Solution 9 - Java

Using just simple loops:

public static void compareSortOrder (List<String> sortOrder, List<String> listToCompare){
        int currentSortingLevel = 0;
        for (int i=0; i<listToCompare.size(); i++){
            System.out.println("Item from list: " + listToCompare.get(i));
            System.out.println("Sorting level: " + sortOrder.get(currentSortingLevel));
            if (listToCompare.get(i).equals(sortOrder.get(currentSortingLevel))){

            } else {
                try{
                    while (!listToCompare.get(i).equals(sortOrder.get(currentSortingLevel)))
                        currentSortingLevel++;
                    System.out.println("Changing sorting level to next value: " + sortOrder.get(currentSortingLevel));
                } catch (ArrayIndexOutOfBoundsException e){
                    
                }

            }
        }
    }

And sort order in List

public static List<String> ALARMS_LIST = Arrays.asList(
            "CRITICAL",
            "MAJOR",
            "MINOR",
            "WARNING",
            "GOOD",
            "N/A");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionakhtarView Question on Stackoverflow
Solution 1 - Javaz7sg ѪView Answer on Stackoverflow
Solution 2 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 3 - JavaSilvio TroiaView Answer on Stackoverflow
Solution 4 - JavailalexView Answer on Stackoverflow
Solution 5 - Javamatt1616View Answer on Stackoverflow
Solution 6 - JavaMariuszSView Answer on Stackoverflow
Solution 7 - JavaThermechView Answer on Stackoverflow
Solution 8 - JavaSidduView Answer on Stackoverflow
Solution 9 - JavafoolerView Answer on Stackoverflow