Как отсортировать HashSet объектов на основе этих критериев?

Я собрал здесь SSCCE:

House.java:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class House {

    private Status currentStatus;
    private String city;
    private Date date;

    public enum Status { AVAILABLE, 
                         SOLD, 
                         CONTINGENT 
    }

    public House(Status s, String c, String d) throws ParseException {
        currentStatus = s;
        city = c;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        date = sdf.parse(d);
    }
}

SortingTest.java:

import java.text.ParseException;
import java.util.HashSet;
import sortingtest.House.Status;    

public class SortingTest {


    public static void main(String[] args) throws ParseException {
        HashSet<House> houses = new HashSet<House>();
        houses.add(new House(Status.AVAILABLE, "New York City", "2007-11-11"));
        houses.add(new House(Status.SOLD, "Los Angeles", "2005-06-11"));
        houses.add(new House(Status.AVAILABLE, "Chicago", "2012-05-03"));
        houses.add(new House(Status.CONTINGENT, "Portland", "2007-10-11"));

        //Sort HashSet of House objects by criteria listed below      

        //sort by Status.AVAILABLE
            //call sort
            //System.out.println("Sorted by available");
            //iterate set and print out sorted houses

        //sort by Status.SOLD
            //call sort
            //System.out.println("Sorted by sold");
            //iterate set and print out sorted houses

        //sort by Status.CONTINGENT
            //call sort
            //System.out.println("Sorted by contingent");
            //iterate set and print out sorted houses

        //sort by City
            //call sort
            //System.out.println("Sorted alphabetically by City");
            //iterate set and print out sorted houses

        //sort by City
            //call sort
            //System.out.println("Sorted reverse alphabetically by City");
            //iterate set and print out sorted houses

        //sort by Date (newest)
            //call sort
            //System.out.println("Sorted by newest date (fewest days on market)");
            //iterate set and print out sorted houses

        //sort by Date (oldest)
            //call sort
            //System.out.println("Sorted oldest date (most days on market)");
            //iterate set and print out sorted houses
    }
}

Итак, в конечном итоге я хочу создать класс SetSorter, где я могу просто вызвать метод, который будет возвращать набор, отсортированный в определенном формате.

Если вы не хотите читать комментарии в коде, я хочу отсортировать на основе:

  • Статус.ДОСТУПЕН
  • Статус.ПРОДАНО
  • Статус.Контингент
  • Город (по алфавиту)
  • Город (в обратном порядке по алфавиту)
  • Дата (наименьшее количество дней на рынке)
  • Дата (большинство дней на рынке)

Я немного почитал об этом, и похоже, что люди предлагают превратить его в TreeSet для сортировки и использования компаратора. Я видел несколько примеров, когда люди либо создают отдельный класс только для компаратора, либо делают реализацию указанного класса сопоставимой.

Чего я не видел, так это того, что кто-то написал дополнительный класс для обработки всей сортировки. Это возможно? Если да, может ли кто-нибудь показать мне, с чего начать? Это кажется несколько более сложным сравнением, чем обычное целочисленное сравнение.

Изменить для уточнения

При сортировке по Status.AVAILABLE я бы хотел, чтобы в наборе отображались объекты:

  • Статус.ДОСТУПЕН (сверху/сначала)
  • Status.CONTINGENT (после Status.AVAILABLE/сек)
  • Status.SOLD (после Status.CONTINGENT/последний)

При сортировке по Status.CONTINGENT я хочу, чтобы набор сортировался следующим образом:

  • Статус.КОНТИНГЕНТ
  • Статус.ПРОДАНО
  • Статус.ДОСТУПЕН

При сортировке по Status.SOLD я хочу, чтобы набор сортировался следующим образом:

  • Статус.ПРОДАНО
  • Статус.КОНТИНГЕНТ
  • Статус.ДОСТУПЕН

Изменить конечную цель №2:

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

Ie:

//sort by date
SetSorter.sortByData(treeSet);    //returns TreeSet sorted by date

//sort by city
SetSorter.sortByCity(treeSet);    //returns TreeSet sorted by City

//sort by other criteria 

Изменить №3

class SortByCity implements Comparator<House> {
    @Override
    public int compare(House h1, House h2) {
        return h1.getCity().compareTo(h1.getCity());
    } 
}


houses = new TreeSet(new SortByCity());

Я думаю, что это был бы простой способ сделать это, но все это были бы маленькие классы и (на мой взгляд) выглядели бы беспорядочно. Кто хочет иметь 7 мини-классов внутри .java?

Может ли кто-нибудь предоставить мне несколько альтернативных примеров?


person WilliamShatner    schedule 20.06.2013    source источник
comment
Что вы подразумеваете под сортировкой на основе Status.AVAILABLE? Это перечисление?   -  person Rohit Jain    schedule 21.06.2013
comment
@RohitJain Я имею в виду все Status.AVAILABLE в верхней части набора. Я отредактирую свой пост, чтобы уточнить.   -  person WilliamShatner    schedule 21.06.2013
comment
Используйте TreeSet и укажите Comparator<YourClass>.   -  person Luiggi Mendoza    schedule 21.06.2013
comment
@WilliamShatner да, поэтому вам понадобятся разные TreeSet для разных способов сортировки данных. Какова ваша конечная цель для начала? Судя по тому, как это выглядит, было бы лучше иметь List<YourObject> и использовать Collections#sort, предоставляя каждый раз пользовательский Comparator<YourObject>.   -  person Luiggi Mendoza    schedule 21.06.2013
comment
Вы можете использовать собственные компараторы для каждого метода и использовать TreeSet(Comparator) вместе с TreeSet#addAll. Все еще не понимаю основной цели выполнения SetSorter.sortXxx.   -  person Luiggi Mendoza    schedule 21.06.2013
comment
@LuiggiMendoza Я впервые пытаюсь это сделать. Это то, как я придумал, так как я буду сортировать информацию в графическом интерфейсе на основе выбора поля со списком. Я открыт для всех предложений о лучших способах сделать это. Я был бы признателен за сообщения с примерами и готов назначить небольшую награду через 2 дня, если это будет необходимо.   -  person WilliamShatner    schedule 21.06.2013
comment
Вам придется возвращать экземпляр производного класса SortedSet, что бы вы ни делали, так как обычные экземпляры Set не нужно сортировать. Таким образом, в основном ваш метод создаст собственный компаратор и поместит все элементы Set в SortedSet, вероятно, TreeSet. Обратите внимание, что если вы сделаете это, вы скопируете только ссылки.   -  person Maarten Bodewes    schedule 21.06.2013
comment
@owlstead Я был бы заинтригован, если бы вы могли показать пример того, что я должен делать. Если я правильно вас понял, я бы передал Set методу, который создаст собственный компаратор и передаст его в TreeSet (как в моем Edit # 3). Кроме того, есть ли недостатки в копировании ссылок вместо их прямого изменения? (я бы предположил, что больше памяти используется?   -  person WilliamShatner    schedule 21.06.2013


Ответы (1)


Вот несколько примеров сортировки. Я не выполнял сортировку по дате или обратному алфавиту (это задание). Обратите внимание на встроенный комментарий о сравнении двух домов со значением 0!

public class HouseSorter {

    enum Status {
        SOLD, AVAILABLE, CONTINGENT;
    }

    /**
     * Immutable house (if a house is sold or not does not change a house, use a
     * Map instead).
     */
    private static class House {
        private final String city;

        House(String city) {
            this.city = city;
        }

        public String getCity() {
            return city;
        }

        @Override
        public String toString() {
            return "House in " + city;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (!House.class.isAssignableFrom(obj.getClass())) {
                return false;
            }
            return this.city.equalsIgnoreCase(((House) obj).city);
        }

        @Override
        public int hashCode() {
            return city.hashCode();
        }
    }

    public static SortedSet<House> sortAlphabetically(Set<House> houses) {
        TreeSet<House> sortedHouses = new TreeSet<House>(
                new Comparator<House>() {
                    @Override
                    public int compare(House o1, House o2) {
                        return o1.getCity().compareTo(o2.getCity());
                    }
                });
        sortedHouses.addAll(houses);
        return sortedHouses;
    }

    public static SortedSet<House> sortByStatus(
            final Map<House, Status> houseStatusMap) {
        TreeSet<House> sortedHouses = new TreeSet<House>(
                new Comparator<House>() {
                    @Override
                    public int compare(House o1, House o2) {
                        int compareByStatus = houseStatusMap.get(o1).compareTo(
                                houseStatusMap.get(o2));
                        if (compareByStatus != 0) {
                            return compareByStatus;
                        }
                        // you need an additional compare, until none of the
                        // houses compare with result 0
                        // otherwise the houses would be equal and therefore
                        // removed from the set
                        return o1.getCity().compareTo(o2.getCity());
                    }
                });
        sortedHouses.addAll(houseStatusMap.keySet());
        return sortedHouses;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        final Map<House, Status> houseStatusMap = new HashMap<House, Status>();
        House house0 = new House("Beverwijk");
        houseStatusMap.put(house0, Status.SOLD);
        House house1 = new House("Opmeer");
        houseStatusMap.put(house1, Status.SOLD);
        House house2 = new House("Amstelveen");
        houseStatusMap.put(house2, Status.AVAILABLE);
        House house3 = new House("Haarlem");
        houseStatusMap.put(house3, Status.CONTINGENT);

        System.out.println(sortAlphabetically(houseStatusMap.keySet()));
        System.out.println(sortByStatus(houseStatusMap));
    }
}
person Maarten Bodewes    schedule 20.06.2013
comment
Спасибо за пример, проверить не успел (завтра сделаю). Требуется ли карта для статуса просто потому, что я хочу сравнить ее несколькими способами? Если бы вместо этого я хотел отсортировать его по порядку перечисления, нужна ли мне карта для сравнения? Еще раз спасибо за отличный пример! Я также попытаюсь найти пример компаратора данных. - person WilliamShatner; 21.06.2013
comment
Нет, это объектно-ориентированный дизайн. Я не думаю, что в принципе статус дома не является частью самого дома. Дверь, наверное, есть, окна тоже, но вывески снаружи нет. - person Maarten Bodewes; 21.06.2013
comment
Еще раз спасибо за пример. Это действительно помогло мне понять, как работают эти компараторы. Однако у меня возникли проблемы с сортировкой по статусу (как вы указали в своем коде, мне нужны дополнительные проверки). Если я просто хочу заказать его по порядковому номеру, как будут выглядеть мои чеки? - person WilliamShatner; 21.06.2013
comment
@WilliamShatner Они упорядочены по порядковому номеру, поскольку функция compareTo по умолчанию для enum классов использует порядковый номер. Только enum не печатается во второй строке. Или, как пишет Sun в JavaDoc: константы перечисления сравнимы только с другими константами перечисления того же типа перечисления. Естественный порядок, реализуемый этим методом, — это порядок, в котором объявлены константы. - person Maarten Bodewes; 22.06.2013