4

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?

user3712130
  • 87
  • 1
  • 3
  • 8
  • 1
    compareTo compares two Players and it is supposed to return a negative, positive or zero number depending if it sorts before, after or at the same position. – eckes Jul 26 '14 at 20:25

3 Answers3

12

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);
    }
}
True Soft
  • 8,675
  • 6
  • 54
  • 83
janos
  • 120,954
  • 29
  • 226
  • 236
5

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.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • 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. – fabian Jul 26 '14 at 20:27
  • I dont understand how to USE the compareTo function. I want to sort the Arraylist "list". – user3712130 Jul 26 '14 at 20:40
  • 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. – Makoto Jul 26 '14 at 20:46
  • Could you please explain a little bit more about why writing `return rating - other.getRating();`? I am totally confused about the compareto function. – Jay Wang Jan 03 '16 at 18:46
  • @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. – Makoto Jan 03 '16 at 18:48
  • @Makoto: Thank you. Can I interpret like the `Collections.sort()` actually is comparing the return value of my `compareTo` function to achieve sorting? – Jay Wang Jan 03 '16 at 18:52
0

Try this.

public class Comparator_Test {

public static void main(String[] args) {
    ArrayList<Players> list = new ArrayList<Players>();      

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

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

    PlayerComparator comparator = new PlayerComparator();
    System.out.println(list);
    Collections.sort(list, comparator);
    System.out.println(list);
}

}

class Players {

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);
            }

     public String toString() {
         return rating + "";
     }
}

class PlayerComparator implements Comparator<Players> {

@Override
public int compare(Players o1, Players o2) {
    if(o1.rating > o2.rating) {
        return 1;
    }
    if(o1.rating < o2.rating) {
        return -1;
    }
    return 0;
}

}
FruitDealer
  • 164
  • 1
  • 11