Как я сортирую список по различным параметрам в синхронизированном различном

Например, в реализации криптографических методов на языках, таких как C, C++. Двоичные файлы, алгоритмы сжатия и логические операции списков - битовая операция всегда хороши =)

94
задан Cœur 31 December 2016 в 18:13
поделиться

6 ответов

Я думаю, что ваш подход с перечислением в основном здравый, но операторы switch действительно нуждаются в более объектно-ориентированном подходе. Рассмотрим:

enum PersonComparator implements Comparator<Person> {
    ID_SORT {
        public int compare(Person o1, Person o2) {
            return Integer.valueOf(o1.getId()).compareTo(o2.getId());
        }},
    NAME_SORT {
        public int compare(Person o1, Person o2) {
            return o1.getFullName().compareTo(o2.getFullName());
        }};

    public static Comparator<Person> decending(final Comparator<Person> other) {
        return new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                return -1 * other.compare(o1, o2);
            }
        };
    }

    public static Comparator<Person> getComparator(final PersonComparator... multipleOptions) {
        return new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                for (PersonComparator option : multipleOptions) {
                    int result = option.compare(o1, o2);
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }
        };
    }
}

Пример использования (со статическим импортом).

public static void main(String[] args) {
    List<Person> list = null;
    Collections.sort(list, decending(getComparator(NAME_SORT, ID_SORT)));
}
193
ответ дан 24 November 2019 в 06:00
поделиться

Один из способов - создать Компаратор , который принимает в качестве аргументов список свойств для сортировки, как показано в этом примере.

public class Person {
    private int id;
    private String name, address;

    public static Comparator<Person> getComparator(SortParameter... sortParameters) {
        return new PersonComparator(sortParameters);
    }

    public enum SortParameter {
        ID_ASCENDING, ID_DESCENDING, NAME_ASCENDING,
        NAME_DESCENDING, ADDRESS_ASCENDING, ADDRESS_DESCENDING
    }

    private static class PersonComparator implements Comparator<Person> {
        private SortParameter[] parameters;

        private PersonComparator(SortParameter[] parameters) {
            this.parameters = parameters;
        }

        public int compare(Person o1, Person o2) {
            int comparison;
            for (SortParameter parameter : parameters) {
                switch (parameter) {
                    case ID_ASCENDING:
                        comparison = o1.id - o2.id;
                        if (comparison != 0) return comparison;
                        break;
                    case ID_DESCENDING:
                        comparison = o2.id - o1.id;
                        if (comparison != 0) return comparison;
                        break;
                    case NAME_ASCENDING:
                        comparison = o1.name.compareTo(o2.name);
                        if (comparison != 0) return comparison;
                        break;
                    case NAME_DESCENDING:
                        comparison = o2.name.compareTo(o1.name);
                        if (comparison != 0) return comparison;
                        break;
                    case ADDRESS_ASCENDING:
                        comparison = o1.address.compareTo(o2.address);
                        if (comparison != 0) return comparison;
                        break;
                    case ADDRESS_DESCENDING:
                        comparison = o2.address.compareTo(o1.address);
                        if (comparison != 0) return comparison;
                        break;
                }
            }
            return 0;
        }
    }
}

Затем его можно использовать в коде например, вот так:

cp = Person.getComparator(Person.SortParameter.ADDRESS_ASCENDING,
                          Person.SortParameter.NAME_DESCENDING);
Collections.sort(personList, cp);
16
ответ дан 24 November 2019 в 06:00
поделиться

Вы можете создать компараторы для каждого свойства, которое вы, возможно, захотите отсортировать, а затем попробовать «объединение в цепочку компараторов» :-) вот так:

public class ChainedComparator<T> implements Comparator<T> {
    private List<Comparator<T>> simpleComparators; 
    public ChainedComparator(Comparator<T>... simpleComparators) {
        this.simpleComparators = Arrays.asList(simpleComparators);
    }
    public int compare(T o1, T o2) {
        for (Comparator<T> comparator : simpleComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}
26
ответ дан 24 November 2019 в 06:00
поделиться

Один из подходов - составить Comparator s. Это может быть библиотечный метод (я уверен, что он существует где-то там).

public static <T> Comparator<T> compose(
    final Comparator<? super T> primary,
    final Comparator<? super T> secondary
) {
    return new Comparator<T>() {
        public int compare(T a, T b) {
            int result = primary.compare(a, b);
            return result==0 ? secondary.compare(a, b) : result;
        }
        [...]
    };
}

Использование:

Collections.sort(people, compose(nameComparator, addressComparator));

В качестве альтернативы обратите внимание, что Collections.sort является стабильной сортировкой. Если производительность не имеет решающего значения, сортировка выполняется во вторичном порядке перед первичным.

Collections.sort(people, addressComparator);
Collections.sort(people, nameComparator);
8
ответ дан 24 November 2019 в 06:00
поделиться

Компараторы позволяют сделать это очень легко и естественно. Вы можете создавать отдельные экземпляры компараторов либо в самом классе Person, либо в классе Service, связанном с вашими потребностями.
Примеры использования анонимных внутренних классов:

    public static final Comparator<Person> NAME_ASC_ADRESS_DESC
     = new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
         int nameOrder = p1.getName().compareTo(p2.getName);
         if(nameOrder != 0) {
           return nameOrder;
         }
         return -1 * p1.getAdress().comparedTo(p2.getAdress());
         // I use explicit -1 to be clear that the order is reversed
      }
    };

    public static final Comparator<Person> ID_DESC
     = new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
         return -1 * p1.getId().comparedTo(p2.getId());
         // I use explicit -1 to be clear that the order is reversed
      }
    };
    // and other comparator instances as needed... 

Если у вас их много, вы также можете структурировать свой код компараторов так, как вам нравится. Например, вы можете:

  • наследовать от другого компаратора,
  • иметь CompositeComparator, который объединяет некоторые существующие компараторы
  • , иметь NullComparator, который обрабатывает нулевые случаи, затем делегирует другому компаратору
  • и т. Д.
]
4
ответ дан 24 November 2019 в 06:00
поделиться

Я думаю, что привязка сортировщиков к классу Person, как в вашем ответе, не является хорошая идея, потому что он объединяет сравнение (обычно бизнес-ориентированное) и объект модели, чтобы они были близки друг к другу. Каждый раз, когда вы хотите изменить / добавить что-то в сортировщике, вам нужно прикоснуться к классу людей, чего обычно вы не хотите делать.

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

2
ответ дан 24 November 2019 в 06:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: