Finding max/min value using Comparable

12,226

Solution 1

The Film class implements Comparable<Film>. What this means is that you must implement a method called compareTo() in class Film that will provide an ordering for objects of this class.

@Override
public int compareTo(Film that) {
    // Order by film length
    return Integer.compare(this.length, that.length);
}

If you only need to sort the objects by film length you can just use Arrays.sort():

Film[] films = new Film[3];
// put the objects into the array
Arrays.sort(films);

Then films[0] will contain the film with the shortest length, while the last element will be the film with the longest length.

If you need to compare by other fields, such as film title, you can create a custom comparator:

class FilmTitleComparator implements Comparator<Film> {
    public int compare(Film a, Film b) {
        return Integer.compare(a.getTitle().length(), b.getTitle().length());
    }
}

And pass it to Arrays.sort()

FilmTitleComparator titleComparator = new FilmTitleComparator();
Arrays.sort(films, titleComparator);

Then films[0] will contain the film with the shortest title, while the last element will be the film with the longest title.

Solution 2

For simplicity, I stubbed your Film class to show a trivial example of how to implement Comparable

public class Film implements Comparable<Film> {
    int maxLength;
    int minLength;
    String title;

    public Film() {
         this.maxLength = 0;
         this.minLength = 0;
         this.title = "";
    }    

    // implement this method to accomplish comparison
    public int compareTo(Film f) {
        int result = 0; // the result to compute.

        if ( this.equals(f) ) {
            result = 0; // these objects are actually equal
        }

        // compare using meaningful data
        else if ( f != null) {
            // check to see if this film is greater than the specified film
            if ( this.getMaxLength() > f.getMaxLength() ) {
                // this film is comparatively greater, return > 0
                result = 1;
            }
            else if ( this.getMaxLength() == f.getMaxLength() ) {
                // these two films are comparatively equal
                result = 0;
            }
            else {
                // this film is comparatively less than the specified film
                result = -1;
            }

            // similarly, you could also check min, but there's really no reason to do that unless your implementation calls for it.
        }
        else {
            throw new IllegalArgumentException("null Film object not allowed here...");
        }

        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Film film = (Film) o;

        if (maxLength != film.maxLength) return false;
        if (minLength != film.minLength) return false;
        if (!title.equals(film.title)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = maxLength;
        result = 31 * result + minLength;
        result = 31 * result + title.hashCode();
        return result;
    }

    public int getMaxLength() {
        return maxLength;
    }

    public void setMaxLength(int maxLength) {
        this.maxLength = maxLength;
    }

    public int getMinLength() {
        return minLength;
    }

    public void setMinLength(int minLength) {
        this.minLength = minLength;
    }

    public String getTitle() {
        return title;
    }

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

To fix your test to actually use such an implementation (it doesn't really test anything...), you could do:

import java.util.Scanner;
public class test {
    public static void main (String[] args){
        Film lastFilm = null; // arbitrary reference to film
        Film[] f = new Film[3];
        Scanner input = new Scanner(System.in);
        for (int i=0;i<3;i++){
            f[i] = new Film(); 

            System.out.println("Enter Film Length:");
            f[i].setLength(input.nextInt());
            input.nextLine();
            System.out.println("Enter Title:");
            f[i].setTitle(input.nextLine());
        }
        input.close();
        for (int i = 0; i < 3; i++) {
            if ( lastFilm != null ) {
                 // compare the films to test. current to last film
                 if ( f[i].compareTo(lastFilm) > 0 ) {
                     System.out.println(f[i].getTitle() + " is greater than " + lastFilm.getTitle()");
                 }
                 else if ( f[i].compareTo(lastFilm) < 0 ) {
                     System.out.println(f[i].getTitle() + " is less than " + lastFilm.getTitle()");
                 }
                 else {
                     System.out.println(f[i].getTitle() + " is equal to " + lastFilm.getTitle()");
                 }
            }
            System.out.println(f[i].toString());
            lastFilm = f[i];
        }
    }
}

Something like this can get you started... good luck

Solution 3

Another solution would be to implement Comparable<Film>:

@Override
public int compareTo(Film that) {
   return this.length - that.length;
}

And use org.apache.commons.lang3.ObjectUtils#min or org.apache.commons.lang3.ObjectUtils#max like:

Film min = ObjectUtils.min(film1, film2);
Film max = ObjectUtils.max(film1, film2);
Share:
12,226
Mark D
Author by

Mark D

Updated on June 25, 2022

Comments

  • Mark D
    Mark D about 2 years

    I have an object class

    public class Film implements Comparable<Film>
    

    I'm using Eclipse and would like to know why Film is underlined in red with the error saying:

    The type Film must implement the inherited abstract method Comparable<Film>.compareTo<Film>

    And now to my main question:

    How would I get the max/min user submitted film length and title?

    My object class Film has getter and setter methods for the Title of the film and the Length of the film and a toString method. Following this article (#3) I created two more methods in my object class:

    public int max(Film maxLength){
        int compareLength = ((Film) maxLength).getLength();
    
        return this.length - compareLength;
    }
    
    public int min(Film minLength){
        int compareLength = ((Film) minLength).getLength();
    
        return compareLength - this.length;
    }
    

    Could I use these to find and print max/min values of the user submitted film lengths?

    If so, how?

    If not, what is the proper way of doing this?

    The test class is as follows:

    import java.util.Scanner;
    public class test {
        public static void main (String[] args){
            Film[] f = new Film[3];
            Scanner input = new Scanner(System.in);
            for (int i=0;i<3;i++){
                f[i] = new Film(); 
    
                System.out.println("Enter Film Length:");
                f[i].setLength(input.nextInt());
                input.nextLine();
                System.out.println("Enter Title:");
                f[i].setTitle(input.nextLine());
            }
            input.close();
            for (int i = 0; i < 3; i++) {
                System.out.println(f[i].toString());
            }
        }
    }
    
    • Ryan J
      Ryan J over 9 years
      The compiler is telling you that you need to implement the required interface method compareTo in your Film class. You'd conceivably use your min/max methods in that implementation to achieve what you want.
    • Mark D
      Mark D over 9 years
      I'm lost as to how I would do that @RyanJ
  • JakeWilson801
    JakeWilson801 over 9 years
    Awesome answer it's really to bad minBy/maxBy doesn't ship standard in java
  • Mark D
    Mark D over 9 years
    Thanks this was simple and clear. Quick question though, is Arrays.sort within the comparable class?
  • Anderson Vieira
    Anderson Vieira over 9 years
    Glad to help. Arrays.sort should be called on a array of the comparable class, not from inside it. In the code you posted I would put it in the main method of class test.
  • Mark D
    Mark D over 9 years
    Is there a way I could separately sort for max or min? Like two different methods?
  • Anderson Vieira
    Anderson Vieira over 9 years
    Yes. You could create a custom MinLengthComparator for min and a MaxLengthComparator for max, by inverting the comparison. Then just pass the comparator to the Arrays.sort method as in the last example.
  • Oleg Sklyar
    Oleg Sklyar over 7 years
    So not sort, use sorted collections or find the value iteratively.