0

I also have an ArrayList items. I have classes derived from Media. Given the code below, how would I sort the arraylist by duration? e.g.

Collections.sort(myMedia, ?);

Here is the class

import java.util.Comparator;


public abstract class Media implements Comparable<Media>{

    private int duration;
    private String title;

    private String imageFileName;

    private static String imageFileDirectory = "src/resources/";

    public Media(String name, int seconds) {
        this.title = name;
        this.duration = seconds;
        this.imageFileName = "";
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }    

    public int getDuration() {
        return duration;
    }

    public void setDuration(int d) {
        this.duration = d;
    }

    public String getImageFileName() {
        return imageFileName;
    }

    public void setImageFileName(String imageFileName) {
        this.imageFileName = imageFileName;
    }

    public static String getImageFileDirectory() {
        return imageFileDirectory;
    }

    public static void setImageFileDirectory(String imageFileDirectory) {
        Media.imageFileDirectory = imageFileDirectory;
    }

    @Override
    public String toString() {
        return  this.getTitle() 
                + ", Duration: " + this.getDuration() + "s, " +
                "Cost: " + costInPence() + "p";
    }

    public abstract int costInPence();

    @Override
    public int compareTo(Media o) {
        return this.getTitle().compareTo(o.getTitle());
    }

    public static class DurationComparator implements Comparator<Media>{
        public int compare(Media m1, Media m2) {
           return m2.getDuration() - m1.getDuration();
        }
    }

    public static class CostComparator implements Comparator<Media>{
        public int compare(Media m1, Media m2) {
           return m2.costInPence() - m1.costInPence();
        }
    }
}
Eminem
  • 7,206
  • 15
  • 53
  • 95

1 Answers1

3

The Collections#sort method has two variants.

The first variant (documentation) only accepts a collection that is to be sorted. It will sort the elements of the collection by their natural order. Therefore the elements must implement the interface Comparable which yields a compareTo method. Your Media objects already implement this interface with a meaningful natural order, namely sorting by their titles:

public abstract class Media implements Comparable<Media> {
    @Override
    public int compareTo(Media o) {
        return this.getTitle().compareTo(o.getTitle());
    }
}

The other variant (documentation) accepts a collection and a Comparator object. It will then sort the elements based on the order defined by the Comparator. You can define Comparator on various ways, since Java 8 it became pretty compact. But first let us take a look at the Comparator you have already defined, it sorts by duration:

public static class DurationComparator implements Comparator<Media> {
    public int compare(Media m1, Media m2) {
       return m2.getDuration() - m1.getDuration();
    }
}

So if you want to sort by titles you should use the first variant. If you want to sort by duration you need to create a new instance of DurationComparator and use the second variant, alternatively use the compact Java 8 statements. The same holds for your CostComparator:

// Sort by title
Collections.sort(myMedia);

// Sort by duration
Collections.sort(myMedia, new DurationComparator<>());

// Sort by duration with Java 8
Collections.sort(myMedia, Comparator.comparingInt(Media::getDuration));

// Sort by cost
Collections.sort(myMedia, new CostComparator<>());

// Sort by cost with Java 8
Collections.sort(myMedia, Comparator.comparingInt(Media::costInPence));

The Comparator#comparing (documentation) method creates a Comparator object that sorts the given elements based on the given keys. The method reference points to a method that yields the keys.

As the methods return int you may choose the method Comparator#comparing (documentation) instead, it is slightly faster since int doesn't need to be boxed into Integer then.

Note that since Java 8 Lists itself provide a sort method too (documentation). So you don't need to call Collections anymore:

myMedia.sort(Comparator.comparingInt(Media::getDuration));

Also note that Comparator now provides some useful methods (documentation), for example to first sort by one key and if keys are equal then sort by a second key:

myMedia.sort(Comparator.comparingInt(Media::getDuration)
    .thenComparing(Media::costInPence));
Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • we can actually make the code much more compact and avoid boxing by doing `myMedia.sort(Comparator.comparingInt(Media::costInPence))`, `myMedia.sort(Comparator.comparingInt(Media::getDuration))` etc. but it's matter of preference. – Ousmane D. Jan 21 '18 at 13:03
  • @Aominè Yeah, just saw that the methods return `int` by myself. Thanks for the hint. – Zabuzard Jan 21 '18 at 13:04