Как я могу заказать TreeMaps или ArrayList, содержащие людей на основе их идентификатора, имени или даты рождения?

Я пробовал почти все, и я не могу заставить свои списки упорядочивать себя. Вот код:

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;

Значения заполнены случайными числами. Моя дата имеет формат даты.

У меня также есть метод toString внутри моего класса person, но по какой-то причине, когда я пытаюсь распечатать свои карты, он дает мне хэш-код (это хэш-код, верно?) Person@a62fc3. Вот мой toString внутри класса person:

             public String toString()
    {

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

    }

Я должен добавить, что я не могу вызвать свой метод toString внутри моего класса person. Потому что он печатает 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();

}

Закомментированный код будет работать, но код, вызывающий toString, не печатает то, что должен.

Сравните с методом внутри моего класса Person:

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;

Я могу предоставить больше кода, если это необходимо.

Сравните метод имени и его вывод. Должен ли я создать список массивов для хранения моих значений, а затем отсортировать их в нем?

    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());
        }
    }

Вывод: 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@83cc673 Person@e03cc673 Person Лицо@de6f34 Лицо@156ee8e Лицо@47b480

Спасибо


person Cody    schedule 19.07.2010    source источник
comment
Можете ли вы опубликовать содержимое метода compareTo?   -  person Michael Myers    schedule 19.07.2010
comment
Как вы реализовали сопоставимый интерфейс в Person?   -  person jjnguy    schedule 19.07.2010
comment
@mmy, если ты ответишь, я не буду голосовать за тебя ... Я не хочу, чтобы люди думали, что я твоя марионетка. :P   -  person jjnguy    schedule 19.07.2010
comment
@ Коди, пожалуйста, отредактируй свой вопрос, добавив то, что ты только что написал в комментарии.   -  person jjnguy    schedule 19.07.2010
comment
@ Джастин, да, я сделал. @mmyers: public int compareTo(Object obj) { Person o = (Person) obj; если (this.id == o.id) { return 0; } если (this.id › o.id) { return 1; } если (this.id ‹ o.id) { return -1; } вернуть 0; Это внутри моего класса человека. У меня есть несколько других сравнений, которые я сделал в компараторах для упорядочения по имени и дате, но я еще не понял, как их использовать.   -  person Cody    schedule 19.07.2010
comment
@Cody: Извините, что стираю ваши правки. Должно быть предупреждение, если я попытаюсь сохранить его, а кто-то другой тем временем отредактировал его, но, похоже, это не очень хорошо работает.   -  person Michael Myers    schedule 19.07.2010
comment
@mmyers Это нормально. Я пытался очистить его, чтобы было легче увидеть, о чем я спрашивал, и немного подчистить мой код. есть идеи? Я понятия не имею, почему метод toString для карты вызывается поверх toString Person, хотя результатом name.get(i) является человек..   -  person Cody    schedule 19.07.2010


Ответы (4)


Ну, я не могу точно определить проблему, у меня есть несколько предложений.

Карты не отсортированы.

Как правило, Map не сортируется, поэтому вы не сможете отсортировать ключи карты. Если вы хотите отсортировать Map, используйте интерфейс SortedMap.

Используйте дженерики, когда это возможно

Интерфейс Comparable является общим. Вероятно, вам следует реализовать Comparable<Person>

Тогда ваш метод compareTo() должен выглядеть так:

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

Разница между Comparator<Person> и Comparable<Person>

Вам нужно взглянуть на интерфейс Comparator, а также на интерфейс Comparable.
Ваш Person должен реализовать сопоставимость таким образом, как вы обычно хотите, чтобы человек был отсортирован. Затем вы должны написать несколько реализаций Comparator.

public classPersonNameComparator implements Comparator<Person> {

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

Важность использования аннотации @Override

Важно всегда использовать аннотацию @Override всякий раз, когда вы пытаетесь переопределить метод суперкласса или реализовать метод интерфейса. Ниже приведены несколько ссылок о том, почему это хорошая идея:

person jjnguy    schedule 19.07.2010
comment
Он использует TreeMap, который является SortedMap. Ограничение переменной интерфейсом Map вообще не должно влиять на порядок. - person Gray; 19.07.2010
comment
Спасибо, Джастин, ваш метод сравнения почти идентичен моему, за исключением параметров. В настоящее время метод сортировки по ID работает нормально. Как я могу отсортировать отсортированную карту? сортируется ли он по умолчанию, когда вы добавляете значения, или вы выполняете для него вызов метода? Мне предложили использовать компараторы, но я понятия не имею, как их использовать. У меня есть 2 класса, которые расширяют компаратор с помощью методов compareTo. Когда я пытаюсь изменить параметры с Obj на Person, чтобы я мог ссылаться на переменные в классе Person, он говорит мне, что я не переопределяю метод и что мне нужно, чтобы реализовать компаратор - person Cody; 20.07.2010
comment
Спасибо! Это решило мою проблему. Спасибо всем за помощь. - person Cody; 20.07.2010
comment
все эти ответы были чрезвычайно полезны, я почти хотел бы распечатать их для заметок.. - person Cody; 20.07.2010
comment
@cody Для этого есть приложение: Stack Printer - person jjnguy; 20.07.2010

Одна проблема, которую я вижу, заключается в том, что TreeMap сортирует по ключу, а не по значению. Ваш compareTo не будет использоваться при сортировке дерева, так как это значение на карте. Поскольку ключом на карте является идентификатор, элементы в дереве должны быть отсортированы по идентификатору человека.

Откуда вы знаете, что карта не отсортирована? Можете ли вы показать нам некоторые результаты, которые показывают, что это не так? Вы случайно не изменили идентификатор Person после того, как он был помещен на карту?

Ой, а что такое names по сравнению с personMap? Кроме того, действительно ли идентификаторы непрерывны, начиная с 1? Что выдает этот код:

for (Person person : peopleMap.values()) {
    System.out.println(person);
}
person Gray    schedule 19.07.2010
comment
Ну, я не могу быть уверен, что карта отсортирована из-за того, что она распечатывает. Если бы я мог заставить его использовать мой метод toString, я бы смог это сказать. Я добавлю вывод и метод для моего CompareByName. - person Cody; 20.07.2010
comment
Что цикл for, который я опубликовал, выдает Коди? Кроме того, если вы скажете p = new Person() ..., а затем выплюнете p.toString(), это сработает? - person Gray; 20.07.2010
comment
Это также заставляет меня задаться вопросом, нужен ли мне compareTo внутри моего личного класса? Потому что treeMap автоматически сортирует свои значения (переменная id является ключом). Есть 20 членов класса person, пронумерованных 1-20, это их ID. Names — это список массивов, который пытался заполнить элементами из peopleMap и отсортировать/распечатать. Не удалось заставить его работать. - person Cody; 20.07.2010
comment
Ваша петля напечатала этот серый цвет: 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 Лицо@e09713 Лицо@de6f34 Лицо@156ee8e Лицо@47b480 Лицо@19b49e6 - person Cody; 20.07.2010
comment
Что-то действительно не так, если ваш toString метод не работает. Код, который вы указали в вопросе, выглядит нормально. Вы уверены, что используете этот класс? Можете ли вы опубликовать весь код на pastie.org? - person Gray; 20.07.2010
comment
pastie.org/1051003 Это мой основной класс, он обрабатывает меню и содержит списки. - person Cody; 20.07.2010
comment
Ваш код выдает мне правильную информацию toString. Может быть, вам нужно очистить среду сборки? Может быть, вы используете старый файл класса по ошибке? Вывод также сортируется по id. Альтернативная сортировка не работает, так как карта может быть отсортирована только одним способом. - person Gray; 20.07.2010
comment
System.out.println(Идентификационный номер: +(names.get(j).id)+tab+ Имя: +tab+peopleMap.get(j).name+tab+ Дата рождения: +peopleMap.get(i).birthdate); Человек p = имена.get(j); Это даже не работает. Втф? - person Cody; 20.07.2010
comment
Извините за новизну, но что вы подразумеваете под очисткой среды сборки? Я проверю, чтобы убедиться, что я использую правильные классы. - person Cody; 20.07.2010
comment
Я могу сортировать списки с помощью ArrayList, верно? Что вы думаете о том, чтобы скопировать все элементы из моей карты в список массивов и упорядочить их? - person Cody; 20.07.2010

Вы использовали метод @Override, чтобы убедиться, что вы действительно переопределяете метод toString? Похоже, он все еще печатает значение по умолчанию toString() (т.е. значение указателя на объект).

person Aviendha    schedule 19.07.2010
comment
Просто добавил его выше моего метода, у меня его не было. Все еще не повезло, он печатает то же самое. - person Cody; 20.07.2010

см. API компаратора.

«Упорядочивание, налагаемое компаратором c на набор элементов S, считается совместимым с равенством тогда и только тогда, когда (compare((Object)e1, (Object)e2)==0) имеет то же логическое значение, что и e1. equals((Object)e2) для каждого e1 и e2 в S."

Я не вижу метода equals в вашем классе Person. Реализация equals по умолчанию сравнивает идентичность. И если вы переопределяете equals, вы должны определить hashCode two.

И этот вопрос: Последовательные результаты Equals(), но непоследовательные TreeMap.containsKey( ) результат

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;
    }
}

Выходы:

[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>]
person Bruno Thomas    schedule 19.07.2010