-1

I have a ArrayList that is made up of Last Names and First Names together based on the following class:

package nameSorting;

import javax.swing.JPanel;

public class Person extends JPanel{

    private String firstName;
    private String lastName;

    public void enterLast(String string){
        lastName = string;
    }
    public void enterFirst(String string){
        firstName = string;
    }
    public String firstName(){
        return firstName;
    }
    public String lastName(){
        return lastName;
    }
    @Override
    public String toString(){
        return firstName + " , " + lastName;
    }
}

My declaration of that ArrayList is as Follows (I do this in another class):

private ArrayList<Person> savedNames = new ArrayList<Person>();

I am then trying to do Collections.sort but it says I need a comparator. I tried to look up how to use it but nothing seemed helpful to my situation because they all sorted numbers and I am trying to sort by Characters.

My goal is to sort the ArrayList based on Last Name Alphabetically. So first A-Z and then there is also another option to sort Z-A. Any ideas on how to make this work?

André Fecteau
  • 140
  • 2
  • 11
  • Did you read [https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html](https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html)? – Radiodef May 13 '15 at 19:53
  • Yes, I did, but I never really every understand the oracle docs. Same thing happened when I started using ArrayList, I had to find someone elses example of how to use them because I found oracles confusing and hard to emulate as well. Thank you though, I will bookmark that page. – André Fecteau May 13 '15 at 20:10

3 Answers3

1
Collections.sort(savedNames, (Person p1, Person p2) -> p1.lastName().compareTo(p2.lastName());
Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
  • 1
    That was a fast downvote. What's wrong with the answer? – Radiodef May 13 '15 at 19:55
  • A one liner with no explanation, that is – Dici May 13 '15 at 19:56
  • It should be noted that this will only work in java 8, but it's a valid answer that doesn't depend on implementing Comparable, which isn't always possible – StormeHawke May 13 '15 at 19:57
  • 1
    The answer is good. Maybe explain what you did here and how OP could modify it to his own needs more. – Felk May 13 '15 at 19:57
  • The answer is correct, but isn't good. See the difference ? If I ask you what is the relativity and you reply me `E = MC^2`, well this is true but does not tell me much – Dici May 13 '15 at 19:57
  • 1
    @Dici Seems like a waste of -1 rep but that's just my take. I'm not sure there is much to explain. – Radiodef May 13 '15 at 19:58
  • thanks @StormeHawke would love to be using Java 8. (That is what I use on my current PC) but the school computers (for this project) use Java 7. and I can't make a Jar file on Java 8 and run it on their computers using Java 7. So I am forced to make my workspace Java 7 compliant. – André Fecteau May 13 '15 at 20:07
1

You can achieve this by implementing the Comparable interface in your Person class:

public class Person extends JPanel implements Comparable {

    ...

    @Override
    public int compareTo(Person other) {
        return this.lastName.compareTo(other.lastName());
    }

}

(code untested) In this case I just delegated the comparing to the last names, so the Persons would get ordered by last name. You can write anything you write into the compareTo. It just needs to return an int <0, ==0 or >0 to determine which object is considered "smaller".

However, Collections.sort() can be used on a list of objects that do not implement the Comparable interface. In this case, you would need to implement a Comparator for the function call. The most elegant way of doing this is with a lambda (Java 8+, copied from Jean-François Savard's answer):

Collections.sort(savedNames, (Person p1, Person p2) ->
    p1.lastName().compareTo(p2.lastName())
);

Without the lambda:

Collections.sort(savedNames, new Comparator<Person>() {
    public int compare(Person p1, Person p2) {
        return p1.lastName().compareTo(p2.lastName());
    }
});

(also untested)

Felk
  • 7,720
  • 2
  • 35
  • 65
  • 2
    This is not necessarily true that you have to implement `Comparable`. A complete answer should include `Collections.sort(Collection, Comparator)`. Sometimes you can't modify the original source, sometimes you want to be able to sort by different properties, in which case `Collections.sort()` is a better option – StormeHawke May 13 '15 at 19:59
  • That's true. With lambdas doing this is probably the most general and elegant way. I modified my answer – Felk May 13 '15 at 20:05
  • For true completeness an implementation using an anonymous inner class (the pre-1.8 way) would be good to show too since a lot of people are still on 1.7. But this is better :) – StormeHawke May 13 '15 at 20:07
  • I tried your without lambda because I have to compile for 1.7 (college computers still on 1.7..) and while it doesn't give any compiler errors, it doesn't actually sort the list. Is there something I have to change to match my code? – André Fecteau May 13 '15 at 23:43
0

You just need to create an order on your type Person by implementing the Comparable interface or an external Comparator.

class Person implements Comparable<Person> {
    @Override
    public compareTo(Person that) {
        // this is a reasonible implementation, but you can have your own
        return String.CASE_INSENSITIVE_ORDER.compare(this.lastName(),that.lastName());
    }
}

Doing this is defining a natural order on Person. This way, you won't have to provide a Comparator when sorting your data. However, you can only have one natural order, and you might need at some point to use a different implementation of the comparison between instances of Person.

In this case, define a new Comparator :

Collections.sort(persons, new Comparator<Person> () {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
});

This is in Java x <= 7 fashion, in Java 8 you can go for :

persons.stream().sorted((p1,p2) -> p1.getAge() - p2.getAge()).collect(Collectors.toList());
Dici
  • 25,226
  • 7
  • 41
  • 82
  • 1
    Well that one is necessary because an anonymous class is implicitly a declaration. So it's essentially the same as trying to do `class Foo implements Comparator<> {...}`. And I didn't try to compile it, I just saw the errors. ; ) Maybe Jean has an excuse for his short answer too. – Radiodef May 13 '15 at 20:34
  • @Dici I'm really curious about your second snippet, why do you convert a list to a stream, then sort it, then re-convert to list ? Why not directly sort it like I did ? This is not what `sorted` is meant to be used. – Jean-François Savard May 14 '15 at 13:33
  • Also, OP said he want to sort based on last name, not age. – Jean-François Savard May 14 '15 at 13:34
  • Also, why not directly call `compareToIgnoreCase` instead of `String.CASE_INSENSITIVE_ORDER.compare` ? – Jean-François Savard May 14 '15 at 13:36
  • @Jean-FrançoisSavard `Collections.sort` is less general purpose, it only applies to `List` whereas passing by a stream allows to do it with any kind of collection, and output any kind of collection (possibly not the same). Also, I prefer this functional style which returns a collection instead of mutating the collection passed as a parameter with a void return type. The last concern could be performance because of the collect operation, but depending on the type of the list, `Collection.sort` might also perform a copy if the list does not implement random access. – Dici May 14 '15 at 14:24
  • @Jean-FrançoisSavard The example of the age is to illustrate the fact that `Comparator` usage enables to write comparison on various criteria whereas implementing `Comparable` only provides a single definition for the ordering. That's typically the kind of things your "answer" lacks of – Dici May 14 '15 at 14:26
  • @Jean-FrançoisSavard because I forgot this method exists. Yes, it would be shorter with it, that's the only point you got right – Dici May 14 '15 at 14:27
  • *" The example of the age is to illustrate the fact that Comparator usage enables to write comparison on various criteria whereas implementing Comparable only provides a single definition for the ordering."*; Make non-sense, you will have to call different comparator. – Jean-François Savard May 14 '15 at 14:28
  • *"Collections.sort is less general purpose, it only applies to List"*. We already know it is a list. You might want to read Collections source-code for better point of view. – Jean-François Savard May 14 '15 at 14:28
  • And what if it wasn't ? I'm not waiting the OP to ask the same question on a `Set`, I give him an answer as complete as possible which will hopefully help him in a wider scope than the original question. This is the difference between an answer and a lazy one-liner – Dici May 14 '15 at 14:30
  • @Jean-FrançoisSavard yeah, exactly... You can write **n** `Comparator`s but implement `Comparable` only **once**. This difference is worth to be mentioned in a **complete answer** – Dici May 14 '15 at 14:33
  • @Dici That's probably why mine was the most upvoted one. Not even mentionning that Radiodef had to correct yours to make it reasonible. Let's ignore the fact that you did not even understand his correction; *"The Java compiler is so stupid when it comes to type inference..."*. – Jean-François Savard May 14 '15 at 14:38
  • @Dici Last point, you might want to change `Java x < 7 fashion` for `Java x <= 7 fashion` in your so-complete answer. – Jean-François Savard May 14 '15 at 15:00
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/77818/discussion-on-answer-by-dici-sort-an-arraylist-that-is-based-on-a-class). – Taryn May 14 '15 at 15:02