Как я могу отсортировать коллекцию пользовательских объектов?

#java #collections

#java #Коллекции

Вопрос:

У меня есть список пользовательских объектов, которые мне нужно отсортировать в следующем порядке: valueOne, valueTwo и valueThree.

Вот мой код

 public class AppRunner {
    public static void main(String[] args) {

        Detail d1 = new Detail("valueOne");
        Detail d2 = new Detail("valueTwo");
        Detail d3 = new Detail("valueFive");
        Detail d4 = new Detail("valueTen");
        Detail d5 = new Detail("valueOne");
        Detail d6 = new Detail("valueOne");

        List<Detail> details = new ArrayList<Detail>(Arrays.asList(d1, d2, d3, d4, d5, d6));

        Collections.sort(details);
        System.out.println(details);
    }
}
 

Мой класс сущностей

 public class Detail implements Comparable<Detail> {

    private String value; // there are three options: valueOne, valueTwo, and some other value

    public Detail(String value) {
        this.value = value;
    }

    @Override
    public int compareTo(Detail detail) {
        String val = detail.getValue();
        if (val.equals(this.value) amp;amp; val.equals("valueOne")) {
            return 1;
        } else if (val.equals(this.value) amp;amp; val.equals("valueTwo")) {
            return -1;
        } else {
            return 0;
        }
    }
    // getter, setters, toString
}
 

Я думаю, что нужна помощь с compareTo методом. В конце мне нужно получить список в таком порядке:

  1. valueOne
  2. valueOne
  3. valueOne
  4. valueTwo
  5. Значение пять

Комментарии:

1. Вы могли бы попробовать использовать карту, где вы можете использовать эти строки в качестве ключей и присваивать им значения в виде целых чисел, таких как valueOne -> 1 . Затем вы можете использовать свой метод compareTo для сравнения значений этих ключей! Если вы только сравните эти строки, он просто отсортирует их для вас в алфавитном порядке.

2. какой вывод вы получите прямо сейчас?

3. У меня нет полнофункционального ответа для вас. Что бы я сделал, так это следующее: я бы ввел строковое перечисление со значениями ваших строк. И в сравнении с я бы просто сравнил их числовой эквивалент. Или — немного проще — ввести новый атрибут в класс Detail, который является простым int . В конструкторе установите значение int, соответствующее заданной строке. Итак, вы вводите свой собственный тип соответствия между строками и некоторым соответствующим числовым значением. В compareTo просто сравните соответствующие целые числа.

4. @Sam Я теперь у меня есть [valueOne, valueTwo, valueFive, valueTen, valueOne, valueOne]

Ответ №1:

Используйте перечисление и сравните ординалы:

 enum ValidValues { valueOne, valueTwo, valueThree }
 

… и затем:

 public int compareTo(Object detail) {
    return Integer.compare(ValidValues.valueOf(this.value).ordinal(),
                           ValidValues.valueOf(((Detail)detail).value).ordinal());
}
 

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

Комментарии:

1. Очень элегантное решение.

Ответ №2:

У вас может быть простой метод получения, который возвращает числовое значение на основе вашего строкового значения и просто возвращает разницу обоих числовых значений в вашем compare() методе (помните, что compare() он должен возвращать 0, если два объекта равны, см. Comparable javadoc .

 public static class Detail implements Comparable<Detail> {

    private String value; // there are three options: valueOne, valueTwo, and some other value

    public Detail(String value) {
        this.value = value;
    }

    @Override
    public int compareTo(Detail detail) {
        return this.getNumericValue() - detail.getNumericValue();
    }

    private int getNumericValue() {
        switch (this.value) {
            case "valueOne": return 1;
            case "valueTwo": return 2;
            default: return 3;
        }
    }

}
 

Ответ №3:

Смотрите Примечание в конце о возможных улучшенных проектах.

Я предлагаю добавить в Detail класс еще одно поле, заполнив его в нужном порядке сортировки и value , и использовать это для сортировки.

 public class Detail implements Comparable<Detail> {

    private String value;
    private int sortOrder;

    public Detail(String value) {
        this.value = value;
        if(value.equals("valueOne") {
            sortOrder = 1;
        }
        if(value.equals("valueTwo") {
            sortOrder = 2;
        }
        ...
        ...
    }
 

Это упрощает compareTo :

 public int compareTo(Detail detail) {
    if(this.sortOrder < detail.sortOrder) {
        return -1;
    }
    if(this.sortOrder == detail.sortOrder) {
        return 0;
    }
    if(this.sortOrder > detail.sortOrder) {
        return 1;
    }
}
 

Примечание:
Вышесказанное является решением вашей проблемы в ее нынешнем виде. Однако у вас могут быть варианты получше. Если вы используете Detail для представления фиксированного набора значений, посмотрите на Enums . Enum s в Java очень мощные и универсальные. Вы можете иметь перечисление, представляющее фиксированный набор значений, и использовать перечисление в своем Detail классе.

Если у вас может быть большой набор значений, которые не являются предопределенными, вы можете иметь Map , который сопоставляет порядок сортировки со значением.

 private static Map<Int, String> sortOrder = new HashMap<Int, String>();

sortOrder.put(1, "valueOne");
...
 

И используйте эту сортировку по карте. В зависимости от вашей ситуации вы можете загрузить эту карту из базы данных, файла при инициализации или просто из-за времени выполнения.

Комментарии:

1. Вот мой результат [valueFive, valueTen, valueOne, valueOne, valueOne, valueTwo]

2. @barbara Это весь ваш набор, ваш ожидаемый результат или то, что вы получаете, когда пытаетесь что-то сделать? Также в моем коде была опечатка, которую я исправил.