Вопрос-ответ

Sorting an ArrayList of objects using a custom sorting order

Сортировка списка объектов с использованием пользовательского порядка сортировки

Я хочу реализовать функцию сортировки для своего приложения адресной книги.

Я хочу отсортировать ArrayList<Contact> contactArray. Contact это класс, который содержит четыре поля: имя, домашний номер, номер мобильного телефона и адрес. Я хочу отсортировать по name.

Как я могу написать пользовательскую функцию сортировки для этого?

Переведено автоматически
Ответ 1

Вот руководство по упорядочиванию объектов:

Хотя я приведу несколько примеров, я бы все равно рекомендовал прочитать это.


Существуют различные способы сортировки ArrayList. Если вы хотите определить естественный (по умолчанию) порядок, то вам нужно разрешить Contact реализовать Comparable. Предполагая, что вы хотите выполнить сортировку по умолчанию на name, тогда сделайте (нулевые проверки опущены для простоты):

public class Contact implements Comparable<Contact> {

private String name;
private String phone;
private Address address;

@Override
public int compareTo(Contact other) {
return name.compareTo(other.name);
}

// Add/generate getters/setters and other boilerplate.
}

чтобы вы могли просто сделать

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

Collections.sort(contacts);

Если вы хотите определить внешний управляемый порядок (который переопределяет естественный порядок), то вам нужно создать Comparator:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Now sort by address instead of name (default).
Collections.sort(contacts, new Comparator<Contact>() {
public int compare(Contact one, Contact other) {
return one.getAddress().compareTo(other.getAddress());
}
});

Вы даже можете определить Comparators в самом Contact, чтобы использовать их повторно, а не создавать заново каждый раз:

public class Contact {

private String name;
private String phone;
private Address address;

// ...

public static Comparator<Contact> COMPARE_BY_PHONE = new Comparator<Contact>() {
public int compare(Contact one, Contact other) {
return one.phone.compareTo(other.phone);
}
};

public static Comparator<Contact> COMPARE_BY_ADDRESS = new Comparator<Contact>() {
public int compare(Contact one, Contact other) {
return one.address.compareTo(other.address);
}
};

}

который может быть использован следующим образом:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Sort by address.
Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS);

// Sort later by phone.
Collections.sort(contacts, Contact.COMPARE_BY_PHONE);

И чтобы завершить начатое, вы могли бы рассмотреть возможность использования универсального компаратора javabean:

public class BeanComparator implements Comparator<Object> {

private String getter;

public BeanComparator(String field) {
this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1);
}

public int compare(Object o1, Object o2) {
try {
if (o1 != null && o2 != null) {
o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]);
o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]);
}
} catch (Exception e) {
// If this exception occurs, then it is usually a fault of the developer.
throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e);
}

return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable<Object>) o1).compareTo(o2));
}

}

который вы можете использовать следующим образом:

// Sort on "phone" field of the Contact bean.
Collections.sort(contacts, new BeanComparator("phone"));

(как вы видите в коде, возможно, нулевые поля уже покрыты, чтобы избежать NPE во время сортировки)

Ответ 2

В дополнение к тому, что уже было опубликовано BalusC, возможно, стоит указать, что начиная с Java 8, мы можем сократить наш код и написать его как:

Collection.sort(yourList, Comparator.comparing(YourClass::getSomeComparableField));

или поскольку у List теперь есть sort метод, также подобный

yourList.sort(Comparator.comparing(YourClass::getSomeComparableField));

Объяснение:

Начиная с Java 8, функциональные интерфейсы (интерфейсы только с одним абстрактным методом - они могут иметь больше стандартных или статических методов) могут быть легко реализованы с помощью:

Поскольку Comparator<T> имеет только один абстрактный метод, int compare(T o1, T o2) это функциональный интерфейс.

Поэтому вместо (пример из @BalusC ответа)

Collections.sort(contacts, new Comparator<Contact>() {
public int compare(Contact one, Contact other) {
return one.getAddress().compareTo(other.getAddress());
}
});

мы можем сократить этот код до:

Collections.sort(contacts, (Contact one, Contact other) -> {
return one.getAddress().compareTo(other.getAddress());
});

Мы можем упростить этот (или любой другой) лямбда-код, пропустив


  • типы аргументов (Java определит их на основе сигнатуры метода)

  • или{return... }

Таким образом, вместо

(Contact one, Contact other) -> {
return one.getAddress().compareTo(other.getAddress();
}

мы можем написать

(one, other) -> one.getAddress().compareTo(other.getAddress())

Также теперь Comparator есть статические методы, такие как comparing(FunctionToComparableValue) или comparing(FunctionToValue, ValueComparator), которые мы могли бы использовать для простого создания компараторов, которые должны сравнивать некоторые конкретные значения из объектов.

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

Collections.sort(contacts, Comparator.comparing(Contact::getAddress)); 
//assuming that Address implements Comparable (provides default order).
Ответ 3

На этой странице рассказывается все, что вам нужно знать о сортировке коллекций, таких как ArrayList.

В принципе, вам нужно


  • создайте свой Contact класс, реализующий Comparable интерфейс, с помощью

    • создание метода public int compareTo(Contact anotherContact) внутри него.


  • Как только вы сделаете это, вы можете просто вызвать Collections.sort(myContactList);,

    • где myContactList это ArrayList<Contact> (или любая другая коллекция Contact).


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

Пример:

public class Contact implements Comparable<Contact> {

....

//return -1 for less than, 0 for equals, and 1 for more than
public compareTo(Contact anotherContact) {
int result = 0;
result = getName().compareTo(anotherContact.getName());
if (result != 0)
{
return result;
}
result = getNunmber().compareTo(anotherContact.getNumber());
if (result != 0)
{
return result;
}
...
}
}
Ответ 4

BalusC и bguiz уже дали очень полные ответы о том, как использовать встроенные компараторы Java.

Я просто хочу добавить, что в Google-collections есть класс Ordering, который более "мощный", чем стандартные компараторы. Возможно, стоит проверить. Вы можете делать интересные вещи, такие как комбинирование порядков, их изменение местами, упорядочивание в зависимости от результата функции для ваших объектов...

Вот сообщение в блоге, в котором упоминаются некоторые из его преимуществ.

java collections arraylist