Java, how to use compareTo to sort an Arraylist

43,414

Solution 1

Instead of making Player implement Comparable, you get more flexibility by implementing Comparator<Player> classes. For example:

class PlayerComparatorByRating implements Comparator<Player> {
    @Override
    public int compare(Player o1, Player o2) {
        return o1.getRating() - o2.getRating();
    }
}

class PlayerComparatorByName implements Comparator<Player> {
    @Override
    public int compare(Player o1, Player o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

After all, Player has multiple fields, it's easy to imagine that sometimes you might want to order players differently. A great advantage of this approach is the single responsibility principle: a Player class does only one thing, encapsulates player data. Instead of adding one more responsibility (sorting), it's better to move that logic in another class.

You could use these comparators with Collections.sort, for example:

Collections.sort(list, new PlayerComparatorByRating());
System.out.println(list);
Collections.sort(list, new PlayerComparatorByName());
System.out.println(list);

Extra tips

Your class seems to be named Players. It's better to rename to Player.

The getName, getRating, getPos methods should not return void and print the result, but return the field values instead.

Use better names for the constructor arguments, for example:

Player(int position, int rating, String name) {
    this.position = position;
    this.rating = rating;
    this.name = name;
}

Use the right type of list to store players:

List<Player> list = new ArrayList<Player>();

Please format your code properly. Any IDE can do that.

Suggested implementation

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

class Player {
    private int position;
    private int rating;
    private final String name;

    Player(int position, int rating, String name) {
        this.position = position;
        this.rating = rating;
        this.name = name;
    }

    public int getRating() {
        return rating;
    }

    public int getPos() {
        return position;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("%s:%d:%d", name, position, rating);
    }
}

class PlayerComparatorByRating implements Comparator<Player> {
    @Override
    public int compare(Player o1, Player o2) {
        return o1.getRating() - o2.getRating();
    }
}

class PlayerComparatorByName implements Comparator<Player> {
    @Override
    public int compare(Player o1, Player o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

public class PlayerComparatorDemo {
    public static void main(String[] args){
        List<Player> list = new ArrayList<Player>();

        Player p1 = new Player(1, 92, "Zlatan");
        Player p2 = new Player(2, 92, "Hazard");
        Player p3 = new Player(1, 82, "Klose");

        list.add(p1);
        list.add(p2);
        list.add(p3);

        Collections.sort(list, new PlayerComparatorByRating());
        System.out.println(list);
        Collections.sort(list, new PlayerComparatorByName());
        System.out.println(list);
    }
}

Solution 2

Don't use a raw type with Comparable. Instead, use Comparable<Players>. This way, you have direct access to the object you care about without having to cast from Object.

The sample compareTo would be this:

public int compareTo(Player other) {
    return rating - other.getRating();
}

Then, you would actually have to...sort it, using Collections.sort().

Collections.sort(list);

The reason for Comparable<Players> is that Comparable itself is defined as taking a generic type T.

Share:
43,414
Admin
Author by

Admin

Updated on July 27, 2020

Comments

  • Admin
    Admin almost 4 years

    Im trying to figure out how to sort an ArrayList using comparable, my code looks like this:

     public class playerComparsion{
    
            public static void main(String[] args){ 
    
    
        ArrayList<Object> list = new ArrayList<Object>();      
    
            Player p1 = new Players(1,92,Zlatan);
        Player p2 = new Players(2,92,Hazard);
        Player p3 = new Players(1,82,Klose);
    
        list.add(p1);
        list.add(p2);
        list.add(p3);
            }
        } 
            class Players implements Comparable{
    
            int position;
                 String name;
                int rating;
    
                public Players(int i, int j, String string)  {
    
                    this.position=i;
                    this.rating=j;
                    this.name=string;
                }
    
                 public void getRating() {
                        System.out.println(this.rating);
                        }
                 public void getPos() {
                        System.out.println(this.position);
                        }
                 public void getName() {
                        System.out.println(this.name);
                        }
    
                @Override
                public int compareTo(Object o) {
                    // TODO Auto-generated method stub
                    return 0;
                }
    
            }
    

    I want to sort the Arraylist based on the attribute rating. I suppose I should use the compareTo function but I have no idea how, can someone help me?

  • fabian
    fabian almost 10 years
    You can access rating directly, if you do it from any method in Player, even for another instance, i.e. other.rating can be used instead of other.getRating(). Also it should be mentioned that the substraction may overflow and produce a illegal value if negative ratings are allowed.
  • Admin
    Admin almost 10 years
    I dont understand how to USE the compareTo function. I want to sort the Arraylist "list".
  • Makoto
    Makoto almost 10 years
    The thing is, it's not you that is using the compareTo function. You're only honoring the contract that you need to establish for Collections.sort() to work properly. It's actually Collections.sort() that makes use of your compareTo method, since it only sorts things that are Comparable. The way you would call it would be Collections.sort(list), but I'll add that into the answer.
  • D. Ben Knoble
    D. Ben Knoble about 9 years
    Just browsing arround; should you do a null check in your compare methods??
  • janos
    janos over 8 years
    Good question. If you allow null values in your collections, then yes, you must add null checks.
  • Jay Wong
    Jay Wong over 8 years
    Could you please explain a little bit more about why writing return rating - other.getRating();? I am totally confused about the compareto function.
  • Makoto
    Makoto over 8 years
    @JayWong: The link in the answer above takes you to the documentation for Comparable. The main principle is that it has to return a negative, zero, or a positive number for less than, equal, or greater than. Subtracting the two fields we care about is the quickest way to accomplish that, provided the values don't underflow.
  • Jay Wong
    Jay Wong over 8 years
    @Makoto: Thank you. Can I interpret like the Collections.sort() actually is comparing the return value of my compareTo function to achieve sorting?
  • MNM
    MNM about 8 years
    Nice, I liked what you did here very infomative