views:

1174

answers:

7

Ok so I have a been making an addressbook application and have pretty much finished all the key features but I am looking to implement a sort feature in the program.

I want to sort an Arraylist which is of a type called Contact (contactArray) which is a separate class which contains four fields; name, home number, mobile number and address. So I was looking into using the collection sort yet am not sure how i'd implement this.

Is this the right sort I should be using / is it possible to use or should I look into making a custom sort?

A: 

You shoud use the Arrays.sort function. The containing classes should implement Comparable.

monksy
Array != ArrayList.
BalusC
Thats why I said Arrays.
monksy
A: 

The Collections.sort is a good sort implementation. If you don't have The comparable implemented for Contact, you will need to pass in a Comparator implementation

Of note:

The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest element in the low sublist is less than the lowest element in the high sublist). This algorithm offers guaranteed n log(n) performance. The specified list must be modifiable, but need not be resizable. This implementation dumps the specified list into an array, sorts the array, and iterates over the list resetting each element from the corresponding position in the array. This avoids the n2 log(n) performance that would result from attempting to sort a linked list in place.

The merge sort is probably better than most search algorithm you can do.

Joshua
+19  A: 

Here's a tutorial about ordering objects: http://java.sun.com/docs/books/tutorial/collections/interfaces/order.html. Although I will give some examples, I would recommend to read it anyway.

You have basically 2 options: 1) let Contact implement Comparable. Assume that you want to sort on name by default, then do:

public class Contact implements Comparable<Contact> {
    private String name; // +getter +setter.

    public int compareTo(Contact other) {
        return name.compareTo(other.name);
    }
}

so that you can just do

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

Collections.sort(contacts);

2) Create a more specific Comparator so that you have a bit more external control over the ordering over contacts:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Now sort by address instead of name (default).
Collections.sort(contacts, new Comparator<Contact>() {
    public int compare(Contact one, Contact other) {
        return one.getAddress().compareTo(other.getAddress());
    }
}); 

An extension of option two, if you sort by different fields at different times, is to define multiple Comparators, and use them by name rather than creating them when used...

public class Contact {
    private String name; // +getter +setter.
    private String phone; // +getter +setter.
    private String email; // +getter +setter.

    public static Comparator COMPARE_BY_ADDRESS = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.getAddress().compareTo(other.getAddress());
        }
    }
    public static Comparator COMPARE_BY_PHONE = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.phone.compareTo(other.phone);
        }
    }
    public static Comparator COMPARE_BY_EMAIL = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.email.compareTo(other.email);
        }
    }

}

then you can do things like:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Then when you want to:
Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS);

// Later:
Collections.sort(contacts, Contact.COMPARE_BY_PHONE);

// Still later: 
Collections.sort(contacts, Contact.COMPARE_BY_EMAIL);

And to cream the top off, you could consider to use a "generic javabean comparator":

class BeanComparator implements Comparator<Object> {
    private String getter;

    public BeanComparator(String field) {
        this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1);
    }

    public int compare(Object o1, Object o2) {
        try {
            if (o1 != null && o2 != null) {
                o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]);
                o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]);
            }
        } catch (Exception e) {
            // If this exception occurs, then it is usually a fault of the developer.
            throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e);
        }

        return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable<Object>) o1).compareTo(o2));
    }
}

which you can use as follows:

// Sort on "email" field of the Contact bean.
Collections.sort(contacts, new BeanComparator("email"));

(as you see in the code, possibly null fields are already covered to avoid NPE's during sort)

BalusC
I'd add the possibility of pre-defining several comparators, and then using them by name...
Stobor
In fact, I just did. Easier than trying to explain myself.
Stobor
@Stobor: Nice, thanks.
BalusC
@BalusC: No probs. I can't take credit for the idea, I got it from `String.CASE_INSENSITIVE_ORDER` and friends but I like it. Makes the resulting code easier to read.
Stobor
Those Comparator definitions should probably also be `static` and maybe `final` too... Or something like that..
Stobor
I added one more solution :)
BalusC
Stobor
Hey thanks for the reply it was really helpful and has greatly improved my understanding of collections.I tried the first one and it did work on the firsname but I need it in a JList ordered by surname so I had a look at the second and just compared a split string, thanks very much :)
Sameera0
@Stobor: this sorts nulls to top. They doesn't necessarily need **both** to be null. @Sameera0: you're welcome.
BalusC
Excellent examples, thanks a bunch!
Patrick
+1  A: 

You need make your Contact classes implement Comparable, and then implement the compareTo(Contact) method. That way, the Collections.sort will be able to sort them for you. Per the page I linked to, compareTo 'returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.'

For example, if you wanted to sort by name (A to Z), your class would look like this:

public class Contact implements Comparable<Contact> {

    private String name;

    // all the other attributes and methods

    public compareTo(Contact other) {
        return this.name.compareTo(other.name);
    }
}
Kaleb Brasee
+4  A: 

This page tells you all you need to know about sorting collections, such as ArrayList.

Basically you need to

  • make your Contact class implement the Comparable interface by
    • creating a method public int compareTo(Contact anotherContact) within it.
  • Once you do this, you can just call Collections.sort(myContactList);,
    • where myContactList is ArrayList<Contact> (or any other collection of Contact).

There's another way as well, involving creating a Comparator class, and you can read about that from the linked page as well.

Example:

public class Contact implements Comparable<Contact> {

    ....

    //return -1 for less than, 0 for equals, and 1 for more than
    public compareTo(Contact anotherContact) {
        int result = 0;
        result = getName().compareTo(anotherContact.getName());
        if (result != 0)
        {
            return result;
        }
        result = getNunmber().compareTo(anotherContact.getNumber());
        if (result != 0)
        {
            return result;
        }
        ...
    }
}
bguiz
+3  A: 

BalusC and bguiz have already given very complete answers on how to use Java's built-in Comparators.

I just want to add that google-collections has an Ordering class which is more "powerful" than the standard Comparators. It might be worth checking out. You can do cool things such as compounding Orderings, reversing them, ordering depending on a function's result for your objects...

Here is a blog post that mentions some of its benefits.

eneveu
Note that google-collections is now a part of Guava (Google's common java libraries), so you might want to depend on Guava (or Guava's collection module) if you want to use the Ordering class.
eneveu
A: 

By using lambdaj you can sort a collection of your contacts (for example by their name) as it follows

sort(contacts, on(Contact.class).getName());

or by their address:

sort(contacts, on(Contacts.class).getAddress());

and so on. More in general, it offers a DSL to access and manipulate your collections in many ways, like filtering or grouping your contacts based on some conditions, aggregate some of their property values, etc.

Mario Fusco