Search code examples
javasortingcomparatorcomparable

Descending sort of object using comparable or comparator


So I have a Hill object that contains information about hills that is obtained from a CSV file. The file looks like this:

import java.io.IOException;
import java.net.URL;
import java.util.*;



public class Hill implements Comparable<Hill>{
    public static final String CSV_FILE_URL = "HIDDEN";
    public static final String DELIMITER = ",";
    public int number;
    public String name,county;
    public double height,lat,lon;


    public Hill(int number,String name,String county,double height,double lat,double lon){
        this.number = number;
        this.name = name;
        this.county = county;
        this.height = height;
        this.lat = lat;
        this.lon = lon;

    }

    public String toString(){
        return(number + ", " + name + ", " + county + ", " + height + ", " + lat + ", " + lon);
    }

    public static List<Hill> readHills() throws IOException{
        String[] fields = new String[0];
        URL url = new URL(CSV_FILE_URL);
        Scanner input = new Scanner(url.openConnection().getInputStream());
        List<Hill> hillList = new ArrayList<>();
        input.nextLine();
        while(input.hasNextLine()){
            fields = input.nextLine().split(DELIMITER);
            Hill hill = new Hill(Integer.parseInt(fields[0]),fields[1],fields[2],Double.parseDouble(fields[3]),Double.parseDouble(fields[4]),Double.parseDouble(fields[5]));
            hillList.add(hill);

        }

        return hillList;
    }


    @Override
    public int compareTo(Hill o) {
        return this.name.compareTo(o.name);
    }
    

}

Inside my exercise class I am currently able to sort the hills alphabetically using the Comparable interface. I then get it to print the first 20 hills.

Now I wish to sort the hills list by height but descending so that I can print out the 20 tallest hills.

import java.io.IOException;
import java.util.*;

public class Exercise5 {

    public static void exercise5d() throws IOException {
        System.out.println("### Exercise 5D ###");
        List listOfHills = Hill.readHills();
        Collections.sort(listOfHills);
        for(int x=0;x<20;x++){
            System.out.println(listOfHills.get(x));
        }
        System.out.println("");

        //Attempt at reversing
        Comparator<Hill> HillComparator = Collections.reverseOrder();
        Collections.sort(listOfHills,HillComparator);
        for(int x=0;x<20;x++){
            System.out.println(listOfHills.get(x));
        }



    }

    public static void main(String[] args) throws IOException {
        exercise5d();
    }
}

Solution

  • Your basic implementation of Comparable compares the names of the hills, it has nothing to do with the height

    How can I adjust Comparable so that it allows me to sort by name and then by height after?

    Create a new Comparator which implements the logic you need to compare the heights and use that with Collections.sort

    Collections.sort(listOfHills, new Comparator<Hill>() {
        @Override
        public int compare(Hill o1, Hill o2) {
            return o2.height > o1.height ? (o2.height == o1.height ? 0 : 1) : -1;
        }
    });
    

    This is one of the reasons I don't normally implement Comparator on objects, unless their is a good business rule associated with how the object should be compared, it's easily to provide a number of custom Comparators (or allow other developers to devise their own) which implement "common" algorithms - but that's me