0

I have tried almost everything and I can't seem to get my lists to order themselves. Here's some code:

private List<Person> names = new ArrayList<Person>(); 
private Map<Integer, Person> peopleMap = new TreeMap <Integer, Person>();
for(int i = 0; i<20; i++)
        {
        Person personOne = new Person();
        peopleMap.put(personOne.id,personOne);
        names.add(personOne);
        }
        Collections.sort(names);
        run();
    }



My Person class:
public class Person implements Comparable {
    public String name;
    public int id;
    public Date birthdate;
    static int idRecord = 0;

The values are filled with randoms. My date has a date format.

I also have a toString method inside my person class, but for some reason when I try to print my maps it gives me the hashcode (this is the hashcode right?) Person@a62fc3. Here is my toString inside the person clasS:

             public String toString()
    {

        char tab = '\t';
        return ("ID Number: "+id+tab+" Name: "+tab+name+tab+" Birthdate: "+(birthdate.toString()));

    }

I should add that I am not able to call my toString method inside my person class. Because it is printing Person@a62fc3.

public void sortByID()
{
    char tab = '\t';

    for (int i = 1; i<20; i++)
    System.out.println((peopleMap.get(i)).toString());
    //System.out.println("ID Number: "+(peopleMap.get(i).id)+tab+" Name: "+tab+peopleMap.get(i).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
    run();

}

The commented code will work but the code calling the toString does not print what it should

Compare to method inside of my Person class:

public int compareTo(Object obj) {
 Person o = (Person) obj; 
if (this.id == o.id) { return 0; }
 if (this.id > o.id) { return 1; } 
if (this.id < o.id) { return -1; } 
return 0;

I can provide more code if it's needed.

Compare by name method and it's output. Should I make an arrayList to store my values in and then sort it in that?

    public void sortByName()
    {
//      char tab = '\t';

        for(int j = 1; j<20; j++)
        {
//          System.out.println("ID Number: "+(names.get(j).id)+tab+" Name: "+tab+peopleMap.get(j).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
            //Person p = names.get(j);
            System.out.println(names.get(j).toString());
        }
    }

Output: Person@10b30a7 Person@1a758cb Person@1b67f74 Person@69b332 Person@173a10f Person@530daa Person@a62fc3 Person@89ae9e Person@1270b73 Person@60aeb0 Person@16caf43 Person@66848c Person@8813f2 Person@1d58aae Person@83cc67 Person@e09713 Person@de6f34 Person@156ee8e Person@47b480

Thanks

Cody
  • 11
  • 1
  • 7
  • Can you post the contents of the `compareTo` method? – Michael Myers Jul 19 '10 at 19:36
  • How did you implement the comparable interface in `Person`? – jjnguy Jul 19 '10 at 19:37
  • @mmy, if you answer I'm not going to upvote you...I don't want people to think I'm your sockpuppet. `:P` – jjnguy Jul 19 '10 at 19:38
  • @Cody, please edit your question to add what you just put in the comment. – jjnguy Jul 19 '10 at 19:39
  • @Justin, yes I did. @mmyers: public int compareTo(Object obj) { Person o = (Person) obj; if (this.id == o.id) { return 0; } if (this.id > o.id) { return 1; } if (this.id < o.id) { return -1; } return 0; That is inside of my person class. I have some other compareTo's I made in comparators for ordering by name and date but I havent figured out how to use them yet. – Cody Jul 19 '10 at 19:39
  • @Cody: So sorry about clobbering your edits. There's supposed to be a warning if I try to save it and someone else has edited it in the meantime, but it doesn't seem to work very well. – Michael Myers Jul 19 '10 at 19:48
  • @mmyers That's fine. I was trying to clean it up so it was easier to see what I was asking and clean up my code a bit. any ideas? I have no idea why the toString method for the map is being called over Person's toString, even though the result of name.get(i) is a person.. – Cody Jul 19 '10 at 19:54

4 Answers4

0

Well, I can't pinpoint the exact problem, I have a few suggestions.

Maps aren't sorted.

In general, an Map is not sorted, so you will not be able to sort the keys of the map. If you want to sort the Map use the SortedMap interface.

Use Generics when possible

The Comparable interface is generic. You should probably be implementing Comparable<Person>

Then your compareTo() method should look like this:

public int compareTo(Person p) {
    if (this.id > p.id) return 1;
    else if (this.id < p.id) return -1;
    else return 0;
}

The difference between Comparator<Person> and Comparable<Person>

You need to take a look at the Comparator interface as well as the Comparable interface.
Your Person should implement comparable in that way that you usually want a person to be sorted. Then you should write some implementations of Comparator.

public classPersonNameComparator implements Comparator<Person> {

    public int compare(Person p1, Person p2) {
        return p1.name.compareTo(p2.name);
    }
}

The importance of using the @Override annotation

It is important to always use the @Override annotation whenever you are trying to override a method of a super class or implement an interface method. The following are a few links regarding why this is a good idea:

Community
  • 1
  • 1
jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • 1
    He's using `TreeMap` which is a `SortedMap`. Limiting the variable to the `Map` interface shouldn't affect the order at all. – Gray Jul 19 '10 at 19:58
  • Thanks Justin, your compare to method is nearly identical to mine except for the params. Currently the method for sorting by ID works fine. How can I sort a sorted map? is it sorted by default when you add the values or do you perform a method call on it? It was suggested to me to use comparators, but I have no idea how to use them. I have 2 classes that extend comparator with compareTo methods. When I try to change the params from Obj to Person so I can reference variables within the Person class, it tells me I am not overriding the method and that I need to in order to implement comparator – Cody Jul 19 '10 at 20:01
  • Thank you! This solved my problem. Thanks to everyone for all the help. – Cody Jul 19 '10 at 22:34
  • all of these responses were extremely helpful, I almost wish I could print them out for notes.. – Cody Jul 20 '10 at 03:04
  • @cody There is an app for that: [Stack Printer](http://stackprinter.appspot.com/) – jjnguy Jul 20 '10 at 03:16
0

One issue that I see is that TreeMap sorts by key not by value. Your compareTo will not be used in the sorting of the tree since it is the value in the map. Since the key in the map is the id the the items in the tree should be sorted by the id of the person.

How do you know that the map isn't sorted? Can you show us some output that shows that it is not? Are you by any chance changing the ID of the Person after it gets put into the map?

Oh, and what is names compared to personMap? Also, are the ids really contiguous starting from 1? What does this code spit out:

for (Person person : peopleMap.values()) {
    System.out.println(person);
}
Gray
  • 115,027
  • 24
  • 293
  • 354
  • Well I can't be sure if the map is sorted because of what it's printing out. If I could get it to use my toString method I would be able to tell. I will add the output and method for my CompareByName. – Cody Jul 19 '10 at 20:05
  • What does the for loop that I posted spit out Cody? Also, if you say `p = new Person()` ... and then spit out `p.toString()` does that work? – Gray Jul 19 '10 at 20:10
  • This also makes me wonder if I need a compareTo inside of my person class? Because a treeMap will sort it's values automatically (the id variable happens to be the key). There are 20 members of person class, indexed 1-20, it's their ID. Names is an arrayList that was attempting to fill with the elements from peopleMap and sort it/print it. Couldnt get it to work. – Cody Jul 19 '10 at 20:11
  • Your loop printed this Gray: Person@10b30a7 Person@1a758cb Person@1b67f74 Person@69b332 Person@173a10f Person@530daa Person@a62fc3 Person@89ae9e Person@1270b73 Person@60aeb0 Person@16caf43 Person@66848c Person@8813f2 Person@1d58aae Person@83cc67 Person@e09713 Person@de6f34 Person@156ee8e Person@47b480 Person@19b49e6 – Cody Jul 19 '10 at 20:12
  • Something is really wrong if you `toString` method does not work. The code you listed in the question looks fine. Are you sure you are using that class? Can you post the entire code to http://pastie.org/ ? – Gray Jul 19 '10 at 20:35
  • http://pastie.org/1051003 That is my Main class, it handles the menu and holds the lists. – Cody Jul 19 '10 at 20:39
  • Your code spits out the right toString information for me. Maybe you need to clean your build environment? Maybe you are using an old class file by mistahge? The output is also sorted by id fine. The alternative sorting doesn't work since the map can only be sorted one way. – Gray Jul 19 '10 at 20:48
  • System.out.println("ID Number: "+(names.get(j).id)+tab+" Name: "+tab+peopleMap.get(j).name+tab+" Birthdate: "+peopleMap.get(i).birthdate); Person p = names.get(j); This doesn't even work. Wtf? – Cody Jul 19 '10 at 20:48
  • Apologies for being new but what do you mean by cleaning one's build environment? I will check to make sure I am using the right classes. – Cody Jul 19 '10 at 20:49
  • I can sort lists with ArrayList right? What do you think of copying all of the elements from my Map into the array list and ordering that? – Cody Jul 19 '10 at 20:51
0

did you use the @Override method to make sure that you are actually overriding the toString method? It looks like it is still printing out the default toString() (ie the value of the pointer to the object).

Aviendha
  • 763
  • 6
  • 16
  • Just added it above my method, I did not have it. Still no luck, it is printing the same. – Cody Jul 19 '10 at 20:39
0

see : comparator API.

"The ordering imposed by a Comparator c on a set of elements S is said to be consistent with equals if and only if (compare((Object)e1, (Object)e2)==0) has the same boolean value as e1.equals((Object)e2) for every e1 and e2 in S."

I don't see an equals method in your Person class. The default implementation of equals compares identity. And if you override equals, you must define hashCode two.

And this question : Consistent Equals() results, but inconsistent TreeMap.containsKey() result

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


public class Person implements Comparable<Person> { 
    public final String name;
    public final int id;
    public final Date birthdate;

    public Person(int id, String name, Date birthdate) {
        this.id = id;
        this.name = name;
        this.birthdate = birthdate;
    }

    public static void main(String[] args) {    
        List<Person> list = new ArrayList<Person>();
        for (int i = 10; i > 0; i--) {
            list.add(new Person(i, "name" + String.valueOf(i), new Date()));
        }
        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Person)) {
            return false;
        }
        return this.id == ((Person)other).id;
    }

    @Override
    public int hashCode() {
        return 41 * id;
    }

    @Override
    public String toString() {
        return "Person<" + id + ">";
    }

    @Override
    public int compareTo(Person other) {
        if (!(other instanceof Person)) {
            throw new IllegalArgumentException();
        }
        return this.id - ((Person)other).id;
    }
}

Outputs :

[Person<10>, Person<9>, Person<8>, Person<7>, Person<6>, Person<5>, Person<4>, Person<3>, Person<2>, Person<1>]
[Person<1>, Person<2>, Person<3>, Person<4>, Person<5>, Person<6>, Person<7>, Person<8>, Person<9>, Person<10>]
Community
  • 1
  • 1
Bruno Thomas
  • 1,179
  • 17
  • 31