-1

We have written the following Movie class below, and we want to be able to use the Collections.sort method to sort an ArrayList<Movie>. We want to sort by the title instance variable, and we want to break ties by the year instance variable. However, our code doesn't work, and we have no idea why.

Example

ArrayList<Movie> movies = new ArrayList<>();
movies.add(new Movie("Good Burger", 1997));
movies.add(new Movie("The Lord of the Rings: The Fellowship of the Ring", 2001));
movies.add(new Movie("Fast Five", 2011));

Collections.sort(movies);

for (Movie m : movies) {
    System.out.println(m);
}

will print the following:

(Fast Five, 2011)
(Good Burger, 1997)
(The Lord of the Rings: The Fellowship of the Ring, 2001)

This is the Movie class:

class Movie implements Comparable<Movie> {

    private final String title;
    private final int year;

    public Movie(String t, int y) {
        this.title = t;
        this.year = y;
    }

    public String toString() {
        return "(" + this.title + ", " + this.year + ")";
    }

    public boolean equals(Object o) {
        return (o instanceof Movie) &&              // check if o is a Movie
               this.year == ((Movie)o).year &&      // check years for equality
               this.title.equals(((Movie)o).title); // check titles for equality
    }

    @Override
    public int compareTo(Movie m) {
        return Integer.compare(this.year, m.year);
    }
}

How does one implement the Comparable interface?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
黄海峰
  • 53
  • 4
  • 4
    `We want to sort by the title instance variable` - then why does your compareTo method compare only the years? – Eran Oct 27 '19 at 07:14
  • Hello eran, that is my careless, I notice that if the title names are same, we compare by year. so I make the year as the parameter. – 黄海峰 Oct 27 '19 at 08:01

3 Answers3

1

One way to do this is to use the Comparator<T> interface:

return Comparator.comparing(Movie::title)
                 .thenComparingInt(Movie::year)
                 .compare(this, m);
Emily
  • 1,030
  • 1
  • 12
  • 20
  • thanks for your quickly response for my question. could you give me more detail for this topic.this is my first time to use the interface Comparable. thank you in advance. – 黄海峰 Oct 27 '19 at 07:29
0

You want to sort by the title, but you have used year in your compareTo method as follows:

@Override
public int compareTo(Movie m) {
    return Integer.compare(m1.getYear(), m2.getYear());
}

Change it to

@Override
public int compareTo(Movie m) {
    int c;
    if(this.title!=null && m!=null && m.getTitle()!=null){  
        c = this.title.compareTo(m.getTitle());
        if (c == 0)
            c = Integer.compare(this.year, m.getYear());            
    }
    return c;
}

For more flexibility, you can use Comparator instead of Comparable as discussed at Java : Comparable vs Comparator

Update: I just went through your question again and realized that first, you want to compare the title and then in case of a tie, you want to compare on year. I have updated the code given above. Additionally, I have provided another approach (using Comparator) below:

public class MovieCompartor implements Comparator<Movie>{
    public int compare(Movie m1, Movie m2) {
        int c;
        if(m!=null && m2!=null){
            if(m1.getTitle()!=null && m2.getTitle()!=null)
                c = m1.getTitle().compareTo(m2.getTitle());
            if (c == 0)
                c = Integer.compare(m1.getYear(), m2.getYear());            
        }
        return c;
    }
}

Then you use Collections.sort(movies, new MovieCompartor()) instead of Collections.sort(movies).

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • hello , thanks for you response, after I change my code as you advise. I meet an error "Failed. 'Collections.sort' was unable to sort the 'ArrayList'", do u know what I should to do to fix this error? thank you. – 黄海峰 Oct 27 '19 at 07:46
  • thanks for detailed answer, I will test it later. :) – 黄海峰 Oct 27 '19 at 08:24
0

You have to first sort by title, then sort by year:

@Override
public int compareTo(Movie m){
    if (this.title.equals(m.title)){         //if titles are same
        return this.year - m.year;           //compare years
    }
    return this.title.compareTo(m.title);    //else just compare titles
}
matrixxd
  • 1
  • 1