views:

231

answers:

2

I'm trying to get familiar with Collections. I have a String which is my key, email address, and a Person object (firstName, lastName, telephone, email). I read in the Java collections chapter on Sun's webpages that if you had a HashMap and wanted it sorted, you could use a TreeMap. How does this sort work? Is it based on the compareTo() method you have in your Person class? I overrode the compareTo() method in my Person class to sort by lastName. But it isn't working properly and was wondering if I have the right idea or not. getSortedListByLastName at the bottom of this code is where I try to convert to a TreeMap. Also, if this is the correct way to do it, or one of the correct ways to do it, how do I then sort by firstName since my compareTo() is comparing by lastName.

import java.util.*;

public class OrganizeThis 
{
    /** 
    Add a person to the organizer

    @param p A person object
    */
    public void add(Person p)
    {   
        staff.put(p.getEmail(), p);
        //System.out.println("Person " + p + "added");
    }

    /**
    * Remove a Person from the organizer.
    *
    * @param email The email of the person to be removed.
    */
    public void remove(String email)
    {
        staff.remove(email);
    }

    /**
    * Remove all contacts from the organizer.
    *
    */
    public void empty()
    {
        staff.clear();
    }

    /**
    * Find the person stored in the organizer with the email address.
    * Note, each person will have a unique email address.
    * 
    * @param email The person email address you are looking for.
    *
    */
    public Person findByEmail(String email)
    {
        Person aPerson = staff.get(email);
        return aPerson;
    }

    /**
    * Find all persons stored in the organizer with the same last name.
    * Note, there can be multiple persons with the same last name.
    * 
    * @param lastName The last name of the persons your are looking for.
    *
    */
    public Person[] find(String lastName)
    {
        ArrayList<Person> names = new ArrayList<Person>();

        for (Person s : staff.values())
        {
            if (s.getLastName() == lastName) {
                names.add(s);
            }
        }
        // Convert ArrayList back to Array
        Person nameArray[] = new Person[names.size()];
        names.toArray(nameArray);
        return nameArray;
    }

    /**
    * Return all the contact from the orgnizer in
    * an array sorted by last name.
    * 
    * @return An array of Person objects.
    *
    */
    public Person[] getSortedListByLastName()
    {
        Map<String, Person> sorted = new TreeMap<String, Person>(staff);
        ArrayList<Person> sortedArrayList = new ArrayList<Person>();
        for (Person s: sorted.values()) {
            sortedArrayList.add(s);
        }
        Person sortedArray[] = new Person[sortedArrayList.size()];
        sortedArrayList.toArray(sortedArray);
        return sortedArray;
    }

    private Map<String, Person> staff = new HashMap<String, Person>();

public static void main(String[] args)
    {
        OrganizeThis testObj = new OrganizeThis();
        Person person1 = new Person("J", "W", "111-222-3333", "[email protected]");
        Person person2 = new Person("K", "W", "345-678-9999", "[email protected]");
        Person person3 = new Person("Phoebe", "Wang", "322-111-3333", "[email protected]");
        Person person4 = new Person("Nermal", "Johnson", "322-342-5555", "[email protected]");
        Person person5 = new Person("Apple", "Banana", "123-456-1111", "[email protected]");
        testObj.add(person1);
        testObj.add(person2);
        testObj.add(person3);
        testObj.add(person4);
        testObj.add(person5);

        System.out.println(testObj.findByEmail("[email protected]"));
        System.out.println("------------" + '\n');

        Person a[] = testObj.find("W");

        for (Person p : a)
        System.out.println(p);

        System.out.println("------------" + '\n');
        a = testObj.find("W");

        for (Person p : a)
        System.out.println(p);

        System.out.println("SORTED" + '\n');
        a = testObj.getSortedListByLastName();
        for (Person b : a) {
            System.out.println(b);
        }
    }
    }

Person class:

public class Person implements Comparable
{
    String firstName;
    String lastName;
    String telephone;
    String email;

    public Person()
    {
       firstName = "";
       lastName = "";
       telephone = "";
       email = "";
    }

    public Person(String firstName)
    {
        this.firstName = firstName;
    }

    public Person(String firstName, String lastName, String telephone, String email) 
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.telephone = telephone;
        this.email = email;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public String getTelephone()
    {
        return telephone;
    }

    public void setTelephone(String telephone)
    {
        this.telephone = telephone;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    public int compareTo(Object o)
    {
        String s1 = this.lastName + this.firstName;
        String s2 = ((Person) o).lastName + ((Person) o).firstName;
        return s1.compareTo(s2);
    }

    public boolean equals(Object otherObject)
    {
        // a quick test to see if the objects are identical
        if (this == otherObject) {
            return true;
        }

        // must return false if the explicit parameter is null
        if (otherObject == null) {
            return false;
        }

        if (!(otherObject instanceof Person)) {
            return false;
        }

        Person other = (Person) otherObject;
        return firstName.equals(other.firstName) && lastName.equals(other.lastName) &&
            telephone.equals(other.telephone) && email.equals(other.email);
    }

    public int hashCode() 
    {
        return this.email.toLowerCase().hashCode();
    }

    public String toString()
    {
        return getClass().getName() + "[firstName = " + firstName + '\n'
                                    + "lastName = " + lastName + '\n'
                                    + "telephone = " + telephone + '\n'
                                    + "email = " + email + "]";
    }


}
+5  A: 

You get the wrong idea, actually.

Here's the gist:

  • Map<K,V> is a mapping from K key to V value
  • TreeMap<K,V> is a SortedMap<K,V> that sorts the keys, not the values

So, a TreeMap<String,Person> would sort based on e-mail addresses, not the Person's first/last names.

If you need a SortedSet<Person>, or a sorted List<Person> then that's a different concept, and yes, Person implements Comparable<Person>, or a Comparator<Person> would come in handy.

API links

Related questions


Example

There are plenty of examples out there already, but here's one more:

import java.util.*;

public class Example {
    static String lastName(String fullName) {
        return fullName.substring(fullName.indexOf(' ') + 1);
    }
    public static void main(String[] args) {
        Map<String,String> map = new TreeMap<String,String>();
        map.put("001", "John Doe");
        map.put("666", "Anti Christ");
        map.put("007", "James Bond");

        System.out.println(map);
        // "{001=John Doe, 007=James Bond, 666=Anti Christ}"
        // Entries are sorted by keys!

        // Now let's make a last name Comparator...
        Comparator<String> lastNameComparator = new Comparator<String>() {
            @Override public int compare(String fullName1, String fullName2) {
                return lastName(fullName1).compareTo(lastName(fullName2));
            }
        };

        // Now let's put all names in a SortedSet...
        SortedSet<String> namesByLastName =
            new TreeSet<String>(lastNameComparator);
        namesByLastName.addAll(map.values());

        System.out.println(namesByLastName);
        // "[James Bond, Anti Christ, John Doe]"
        // Names sorted by last names!

        // Now let's use a List instead...
        List<String> namesList = new ArrayList<String>();
        namesList.addAll(map.values());
        System.out.println(namesList);
        // "[John Doe, James Bond, Anti Christ]"
        // These aren't sorted yet...

        Collections.sort(namesList);
        System.out.println(namesList);
        // "[Anti Christ, James Bond, John Doe]"
        // Sorted by natural ordering!

        // Now let's sort by string lengths...
        Collections.sort(namesList, new Comparator<String>() {
            @Override public int compare(String s1, String s2) {
                return Integer.valueOf(s1.length()).compareTo(s2.length());
            }
        });
        System.out.println(namesList);
        // "[John Doe, James Bond, Anti Christ]"
        // SUCCESS!!!
    }
}
polygenelubricants
There are plenty of CORRECT and relevant information in the related questions. "Sorting an ArrayList of Contacts" in particular is very similar, and shows how to sort by address, by phone, etc.
polygenelubricants
A: 

As polygenelubricants nicely explained, a SortedMap is sorted by the key, not by the value.

However, it's with help of LinkedHashMap possible to reorder a Map the way you want. A LinkedHashMap maintains insertion order like a List does.

First step is to get hold of the key/value pairs in a sortable data structure, e.g. List<Entry<K, V>> which you in turn sort using Collections#sort() with help of a Compatator<Entry<K, V>> and finally repopulate a LinkedHashMap with it (not a HashMap or you will lose the ordering again).

Here's a basic example (leaving obvious runtime exception handling aside):

// Prepare.
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "bar");
map.put("bar", "waa");
map.put("waa", "foo");
System.out.println(map); // My JVM shows {waa=foo, foo=bar, bar=waa}

// Get entries and sort them.
List<Entry<String, String>> entries = new ArrayList<Entry<String, String>>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<String, String>>() {
    public int compare(Entry<String, String> e1, Entry<String, String> e2) {
        return e1.getValue().compareTo(e2.getValue());
    }
});

// Put entries back in an ordered map.
Map<String, String> orderedMap = new LinkedHashMap<String, String>();
for (Entry<String, String> entry : entries) {
    orderedMap.put(entry.getKey(), entry.getValue());
}

System.out.println(orderedMap); // {foo=bar, waa=foo, bar=waa}

Needless to say that this is after all not the right datastructure for your purpose ;)

BalusC