I have a class, Library, that contains an array of Book objects, and I need to sort the array based off the properties of Book, either Title or PageNumber. The problem is im not allowed to use the Comparable class with Book. How would you recommend I sort the array of Books in library? Write my own sort? Or is there an easier way? If you need snippets of code, just ask!
Asked
Active
Viewed 5.8k times
20
-
And can you use a `Comparator`? – João Silva Sep 16 '12 at 19:03
-
I can in Library, but not in Book. – samuraiseoul Sep 16 '12 at 19:04
-
1Is this limitation artificial, as in an assignment, or there is another reason? – Bruno Kim Sep 16 '12 at 19:12
-
It's an assignment, so artificial. – samuraiseoul Sep 16 '12 at 19:15
4 Answers
31
You can provide a Comparator
for comparing any type you wish, Comparable
or otherwise.
For Arrays and Collections you use
Arrays.sort(array, myComparator);
Collections.sort(list, myComparator);
Even sorted collections like TreeSet can take a custom Comparator
e.g.
Collections.sort(books, new Comparator<Book>() {
public int compare(Book b1, Book b2) {
return if b1 is greater return +1, if b2 is smaller return -1 otherwise 0
}
});

Jasper Denkers
- 111
- 5

Peter Lawrey
- 525,659
- 79
- 751
- 1,130
-
Okay, can you help me with a basic implementation? Im pretty new to Java, so do I declare Library with public class Library implements Comparable
{} ? – samuraiseoul Sep 16 '12 at 19:06 -
1A Comparator is a stand alone class which is additional to your class. There is many ways you can do it but a common choice is to use an anonymous class, added an example. – Peter Lawrey Sep 16 '12 at 19:09
-
Alrighty, I see the basics of this, the last thing would be where to implement this in my code, like say I had a function in Library public void sort(){} would that be where I throw this code in? And then to sort it I would use Arrays.sort(arrayname, ?) – samuraiseoul Sep 16 '12 at 19:13
-
1You would use it wherever you need to sort the collection. i.e. it can be anywhere and where is best is up to you. – Peter Lawrey Sep 16 '12 at 19:14
-
okay, and lastly, I would actually sort it with Arrays.sort(arrayname, (what goes here?)); Adn the what goes here is an anonymous function right? – samuraiseoul Sep 16 '12 at 19:17
-
1Just like the example yes. If the whole array is no populated you need to use `Arrays.sort(array, start, end, comparator);` – Peter Lawrey Sep 16 '12 at 19:19
-
And that is used if say I declare an array of size 50, but only am using 20 elements at the time? So I would have start be 0, and end be the number of books the library currently has? – samuraiseoul Sep 16 '12 at 19:21
-
For some reason I'm trying this in Java 8 and am getting a `ClassCastException` when passing in an array of non `Comparable` and a correspondingle `Comparator`: ```java.lang.ClassCastException: java.net.Inet6Address cannot be cast to java.lang.Comparable at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) at java.util.ComparableTimSort.sort(ComparableTimSort.java:188) at java.util.Arrays.sort(Arrays.java:1246) at java.util.Arrays.sort(Arrays.java:1433) ``` anyone knows if this changed in Java 8? – Roberto Andrade Mar 12 '17 at 11:48
-
@RobertoAndrade That error means you are not passing a Comparator to the `sort` as above. This is no different in Java 8. – Peter Lawrey Mar 12 '17 at 11:52
-
Looks like they are using Tim Peter sort algorithm and the implementation forces the array elements to be `Comparable`. Would be nice if the actual `Arrays.sort(T[], Comparable super T>)` and corresponding `Collections.sort` contract enforced `T super Comparable` if that's now the case. – Roberto Andrade Mar 12 '17 at 11:53
-
I am passing a `Comparator
` and an array of `InetAddress` to the `sort` method. @PeterLawrey – Roberto Andrade Mar 12 '17 at 11:54 -
I was looking at the [source code](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/ComparableTimSort.java#309) of `ComparableTimSort` and it looks like they cast every array element into a `Comparable`. – Roberto Andrade Mar 12 '17 at 11:55
-
@RobertoAndrade that code is only called if a Comparator is not used.If you use a Comparator, then `TimSort` not `ComparableTimSort` is used. – Peter Lawrey Mar 12 '17 at 12:01
-
@RobertoAndrade from the stack trace Arrays line 1433, you are executing this code `if (c == null) { sort(a);` so while you are calling the right method, the Comparator is null. – Peter Lawrey Mar 12 '17 at 12:04
-
1I was able to confirm this was indeed a user error, my comparator was null at the time I was invoking `sort`. Thanks for helping sorting it out @PeterLawrey. – Roberto Andrade Mar 12 '17 at 12:05
-
1
8
If you can use Comparators
, write one for each type of sorting you need, e.g., ascending for book title and descending for page number. The compare
method of a Comparator
must return positive if the first argument is larger than the second, negative if the first is smaller and zero if they are equal.
import java.util.Comparator;
import java.util.List;
import java.util.Arrays;
class Book{
String title;
int pageNumber;
public Book(String title, int pageNumber){
this.title = title;
this.pageNumber = pageNumber;
}
String getTitle(){ return title; }
int getPageNumber(){ return pageNumber; }
public String toString(){
return "(" + title + ", " + pageNumber + " pages)";
}
}
public class Library{
// These variables are static because you don't need multiple copies
// for sorting, as they have no intrinsic state.
static private Comparator<Book> ascTitle;
static private Comparator<Book> descPageNumber;
// We initialize static variables inside a static block.
static {
ascTitle = new Comparator<Book>(){
@Override
public int compare(Book b1, Book b2){
return b1.getTitle().compareTo(b2.getTitle());
}
};
descPageNumber = new Comparator<Book>(){
@Override
public int compare(Book b1, Book b2){
// Java 7 has an Integer#compare function
return Integer.compare(b1.getPageNumber(), b2.getPageNumber());
// For Java < 7, use
// Integer.valueOf(n1).compareTo(n2);
// DO NOT subtract numbers to make a comparison such as n2 - n1.
// This can cause a negative overflow if the difference is larger
// than Integer.MAX_VALUE (e.g., n1 = 2^31 and n2 = -2^31)
}
};
}
private Book[] books;
public Book[] getBooks(){ return books; }
public void sortAscTitle(){
Arrays.sort(books, ascTitle);
}
public void sortDescPageNumber(){
Arrays.sort(books, descPageNumber);
}
public Library(Book[] books){
this.books = books;
}
public static void main(String[] args){
Library library = new Library( new Book[]{
new Book("1984", 123),
new Book("I, Robot", 152),
new Book("Harry Potter and the Philosopher's Stone", 267),
new Book("Harry Potter and the Goblet of Fire", 759),
new Book("The Bible", 1623)
});
library.sortAscTitle();
System.out.println(Arrays.toString(library.getBooks()));
library.sortDescPageNumber();
System.out.println(Arrays.toString(library.getBooks()));
}
}

Bruno Kim
- 2,300
- 4
- 17
- 27
-
Thanks! Really nice! I was using Peter's suggestion for it, and that style of implementation jives a bit better in my class, however, this is really great too, and I was having trouble with the returns on it, so seeing that code really helped me a lot! Thanks so much! Ill be coming back to this question for reference every time I need to sort anything! – samuraiseoul Sep 16 '12 at 20:20
1
Stick this in your Library:
java.util.Collections.sort(bookList, bookComparator);

David Soroko
- 8,521
- 2
- 39
- 51
-
1booklist would be the name of the array right? What about bookComparator? – samuraiseoul Sep 16 '12 at 19:09
-
bookComparator will be an instance of implementation of the Comparator interface that takes into account book specific properties (e.g.title, ISBN, etc..) . In this example bookList is a List which is easy to get from an array but you can stick to array and do: Arrays.sort(bookArray, bookComparator); – David Soroko Sep 16 '12 at 19:19
0
Expanding @PeterLawrey's answer to Java 8, you can now use a Lambda Expression instead of a Comparable<T>
delegate:
Collections.sort(books, (firstBook, secondBook -> b1 is greater return +1,
if b2 is smaller return -1 otherwise 0));

Yuval Itzchakov
- 146,575
- 32
- 257
- 321