Я хочу сортувати свої об'єкти за спаданням за допомогою компаратора.
class Person {
private int age;
}
Тут я хочу відсортувати масив об’єктів Person.
Як я можу це зробити?
Відповіді:
Ви можете зробити низхідний сорт визначеного користувачем класу таким чином, перевизначивши метод compare () ,
Collections.sort(unsortedList,new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
return b.getName().compareTo(a.getName());
}
});
Або за допомогою Collection.reverse()сортування за спаданням як користувач Prince згадував у своєму коментарі .
І ви можете зробити висхідне сортування таким чином,
Collections.sort(unsortedList,new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
});
Замініть наведений вище код лямбда-виразом (Java 8 і далі), і ми отримаємо стислий вислів:
Collections.sort(personList, (Person a, Person b) -> b.getName().compareTo(a.getName()));
Починаючи з Java 8, List має метод sort (), який приймає Comparator як параметр (більш стислий):
personList.sort((a,b)->b.getName().compareTo(a.getName()));
Тут aі bвиводяться як тип особи за лямбда-виразом.
compareToIgnoreCaseце також зручно при порівнянні Stringоб’єктів, найчастіше я використовую це замість простоcompareTo
Для чого тут варто - це моя стандартна відповідь. Єдине, що нове тут - це те, що використовує Collections.reverseOrder (). Плюс, це подає всі пропозиції на одному прикладі:
/*
** Use the Collections API to sort a List for you.
**
** When your class has a "natural" sort order you can implement
** the Comparable interface.
**
** You can use an alternate sort order when you implement
** a Comparator for your class.
*/
import java.util.*;
public class Person implements Comparable<Person>
{
String name;
int age;
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name + " : " + age;
}
/*
** Implement the natural order for this class
*/
public int compareTo(Person p)
{
return getName().compareTo(p.getName());
}
static class AgeComparator implements Comparator<Person>
{
public int compare(Person p1, Person p2)
{
int age1 = p1.getAge();
int age2 = p2.getAge();
if (age1 == age2)
return 0;
else if (age1 > age2)
return 1;
else
return -1;
}
}
public static void main(String[] args)
{
List<Person> people = new ArrayList<Person>();
people.add( new Person("Homer", 38) );
people.add( new Person("Marge", 35) );
people.add( new Person("Bart", 15) );
people.add( new Person("Lisa", 13) );
// Sort by natural order
Collections.sort(people);
System.out.println("Sort by Natural order");
System.out.println("\t" + people);
// Sort by reverse natural order
Collections.sort(people, Collections.reverseOrder());
System.out.println("Sort by reverse natural order");
System.out.println("\t" + people);
// Use a Comparator to sort by age
Collections.sort(people, new Person.AgeComparator());
System.out.println("Sort using Age Comparator");
System.out.println("\t" + people);
// Use a Comparator to sort by descending age
Collections.sort(people,
Collections.reverseOrder(new Person.AgeComparator()));
System.out.println("Sort using Reverse Age Comparator");
System.out.println("\t" + people);
}
}
Я б створив компаратор для класу person, який можна параметризувати за допомогою певної поведінки сортування. Тут я можу встановити порядок сортування, але його можна змінити, щоб дозволити сортування і для інших атрибутів особи.
public class PersonComparator implements Comparator<Person> {
public enum SortOrder {ASCENDING, DESCENDING}
private SortOrder sortOrder;
public PersonComparator(SortOrder sortOrder) {
this.sortOrder = sortOrder;
}
@Override
public int compare(Person person1, Person person2) {
Integer age1 = person1.getAge();
Integer age2 = person2.getAge();
int compare = Math.signum(age1.compareTo(age2));
if (sortOrder == ASCENDING) {
return compare;
} else {
return compare * (-1);
}
}
}
(сподіваюсь, що він компілюється зараз, у мене під рукою немає IDE або JDK, кодованого "сліпим")
Редагувати
Завдяки Томасу відредагував код. Я б не сказав, що використання Math.signum є хорошим, продуктивним, ефективним, але я хотів би зберегти це як нагадування, що метод compareTo може повернути будь-яке ціле число і множення на (-1) не вдасться, якщо реалізація повертає Integer.MIN_INTEGER ... І я видалив сеттер, оскільки він досить дешевий для створення нового PersonComparator саме тоді, коли це потрібно.
Але я продовжую боротися, бо це свідчить про те, що я покладаюсь на існуючу порівняльну реалізацію. Міг зробити щось подібне, Comparable<Integer> age1 = new Integer(person1.getAge());але це виглядало надто негарно. Ідея полягала в тому, щоб показати зразок, який можна було б легко адаптувати до інших атрибутів Людини, таких як ім’я, день народження як Дата тощо.
compare * (-1)схильний до переповнення. Я зробив ту ж помилку у своєму початковому дописі.
new Reverse(new PersonComparator())
Integer age1 = ...;має бокс накладні витрати.
String[] s = {"a", "x", "y"};
Arrays.sort(s, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println(Arrays.toString(s));
-> [y, x, a]
Тепер вам потрібно застосувати компаратор для вашого класу Person. Щось на зразок (для зростання): compare(Person a, Person b) = a.id < b.id ? -1 : (a.id == b.id) ? 0 : 1або Integer.valueOf(a.id).compareTo(Integer.valueOf(b.id)).
Щоб мінімізувати плутанину, вам слід застосувати висхідний компаратор і перетворити його на спадний за допомогою обгортки ( наприклад, цієї ) new ReverseComparator<Person>(new PersonComparator()).
-1 * Integer.MIN_VALUE == Integer.MIN_VALUE. Що не те, що ти хочеш. Я поміняв аргументи, які і так легше.
Integer.compareзгадує у своїй документації наступне:, The value returned is identical to what would be returned by: Integer.valueOf(x).compareTo(Integer.valueOf(y))тому ви можете Integer.compareзамість цього використовувати .
Використання колекцій Google:
class Person {
private int age;
public static Function<Person, Integer> GET_AGE =
new Function<Person, Integer> {
public Integer apply(Person p) { return p.age; }
};
}
public static void main(String[] args) {
ArrayList<Person> people;
// Populate the list...
Collections.sort(people, Ordering.natural().onResultOf(Person.GET_AGE).reverse());
}
package com.test;
import java.util.Arrays;
public class Person implements Comparable {
private int age;
private Person(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Object o) {
Person other = (Person)o;
if (this == other)
return 0;
if (this.age < other.age) return 1;
else if (this.age == other.age) return 0;
else return -1;
}
public static void main(String[] args) {
Person[] arr = new Person[4];
arr[0] = new Person(50);
arr[1] = new Person(20);
arr[2] = new Person(10);
arr[3] = new Person(90);
Arrays.sort(arr);
for (int i=0; i < arr.length; i++ ) {
System.out.println(arr[i].age);
}
}
}
Ось один із способів зробити це.
Клас java.util.Collection s має метод сортування, який бере список та спеціальний порівняльник . Ви можете визначити власний компаратор, щоб сортувати об’єкт Person, як завгодно.
Collections.reverseOrder(...)для сортування за спаданням.