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();
        }
    }
}
7
  • Collections.sort(myMedia, new DurationComparator()); Commented Jan 21, 2018 at 12:47
  • Excellent. It works :) Commented Jan 21, 2018 at 12:49
  • You already wrote Comparator! Commented Jan 21, 2018 at 12:49
  • If you want to sort by duration you should use the DurationComparator. If you want to sort by title you don't need to specify any comparator as your Media objects define this as their natural order (by using Comparable with compareTo). Commented Jan 21, 2018 at 12:51
  • stackoverflow.com/questions/22314009/… Commented Jan 21, 2018 at 12:55

1 Answer 1

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));
Sign up to request clarification or add additional context in comments.

2 Comments

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.
@Aominè Yeah, just saw that the methods return int by myself. Thanks for the hint.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.