Câu trả lời:
Bạn có thể sử dụng Collections.sort
như sau:
private static void order(List<Person> persons) {
Collections.sort(persons, new Comparator() {
public int compare(Object o1, Object o2) {
String x1 = ((Person) o1).getName();
String x2 = ((Person) o2).getName();
int sComp = x1.compareTo(x2);
if (sComp != 0) {
return sComp;
}
Integer x1 = ((Person) o1).getAge();
Integer x2 = ((Person) o2).getAge();
return x1.compareTo(x2);
}});
}
List<Persons>
bây giờ được sắp xếp theo tên, sau đó theo tuổi.
String.compareTo
"So sánh hai chuỗi từ vựng" - từ các tài liệu .
Collections.sort
là một phương thức tĩnh trong thư viện Bộ sưu tập gốc. Nó thực hiện sắp xếp thực tế, bạn chỉ cần cung cấp Trình so sánh xác định cách so sánh hai yếu tố trong danh sách của bạn: điều này đạt được bằng cách cung cấp compare
phương thức thực hiện của riêng bạn .
Comparable
. Xem câu trả lời của @ berry120
Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparingInt(Person::getAge);
Đối với những người có thể sử dụng API phát trực tuyến Java 8, có một cách tiếp cận gọn gàng hơn được ghi lại ở đây: Lambdas và sắp xếp
Tôi đang tìm kiếm tương đương với C # LINQ:
.ThenBy(...)
Tôi đã tìm thấy cơ chế trong Java 8 trên Trình so sánh:
.thenComparing(...)
Vì vậy, đây là đoạn trích thể hiện thuật toán.
Comparator<Person> comparator = Comparator.comparing(person -> person.name);
comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
Kiểm tra liên kết ở trên để biết cách gọn gàng hơn và giải thích về cách suy luận kiểu Java làm cho nó khó hiểu hơn một chút so với LINQ.
Dưới đây là bài kiểm tra đơn vị đầy đủ để tham khảo:
@Test
public void testChainedSorting()
{
// Create the collection of people:
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("Dan", 4));
people.add(new Person("Andi", 2));
people.add(new Person("Bob", 42));
people.add(new Person("Debby", 3));
people.add(new Person("Bob", 72));
people.add(new Person("Barry", 20));
people.add(new Person("Cathy", 40));
people.add(new Person("Bob", 40));
people.add(new Person("Barry", 50));
// Define chained comparators:
// Great article explaining this and how to make it even neater:
// http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
Comparator<Person> comparator = Comparator.comparing(person -> person.name);
comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
// Sort the stream:
Stream<Person> personStream = people.stream().sorted(comparator);
// Make sure that the output is as expected:
List<Person> sortedPeople = personStream.collect(Collectors.toList());
Assert.assertEquals("Andi", sortedPeople.get(0).name); Assert.assertEquals(2, sortedPeople.get(0).age);
Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
Assert.assertEquals("Bob", sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
Assert.assertEquals("Bob", sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
Assert.assertEquals("Bob", sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
Assert.assertEquals("Dan", sortedPeople.get(7).name); Assert.assertEquals(4, sortedPeople.get(7).age);
Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3, sortedPeople.get(8).age);
// Andi : 2
// Barry : 20
// Barry : 50
// Bob : 40
// Bob : 42
// Bob : 72
// Cathy : 40
// Dan : 4
// Debby : 3
}
/**
* A person in our system.
*/
public static class Person
{
/**
* Creates a new person.
* @param name The name of the person.
* @param age The age of the person.
*/
public Person(String name, int age)
{
this.age = age;
this.name = name;
}
/**
* The name of the person.
*/
public String name;
/**
* The age of the person.
*/
public int age;
@Override
public String toString()
{
if (name == null) return super.toString();
else return String.format("%s : %d", this.name, this.age);
}
}
Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparing(Person::getAge);
thenComparingInt
cho tuổi (int)
Collections.sort(people, comparator);
thay thế?
Sử dụng cách tiếp cận Luồng Java 8 ...
//Creates and sorts a stream (does not sort the original list)
persons.stream().sorted(Comparator.comparing(Person::getName).thenComparing(Person::getAge));
Và cách tiếp cận Lambda Java 8 ...
//Sorts the original list Lambda style
persons.sort((p1, p2) -> {
if (p1.getName().compareTo(p2.getName()) == 0) {
return p1.getAge().compareTo(p2.getAge());
} else {
return p1.getName().compareTo(p2.getName());
}
});
Cuối cùng ...
//This is similar SYNTAX to the Streams above, but it sorts the original list!!
persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));
Bạn cần phải tự thực hiện Comparator
và sau đó sử dụng nó: ví dụ:
Arrays.sort(persons, new PersonComparator());
Bộ so sánh của bạn có thể trông giống như thế này:
public class PersonComparator implements Comparator<? extends Person> {
public int compare(Person p1, Person p2) {
int nameCompare = p1.name.compareToIgnoreCase(p2.name);
if (nameCompare != 0) {
return nameCompare;
} else {
return Integer.valueOf(p1.age).compareTo(Integer.valueOf(p2.age));
}
}
}
Đầu tiên bộ so sánh so sánh các tên, nếu chúng không bằng nhau, nó trả về kết quả từ việc so sánh chúng, nếu không, nó sẽ trả về kết quả so sánh khi so sánh độ tuổi của cả hai người.
Mã này chỉ là một bản nháp: bởi vì lớp này không thay đổi, bạn có thể nghĩ đến việc xây dựng một singleton của nó, thay vào đó tạo ra một thể hiện mới cho mỗi cách sắp xếp.
Bạn có thể sử dụng phương pháp Lambda Java 8 để đạt được điều này. Như thế này:
persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));
Comparable<Person>
Ví dụ, có lớp người của bạn triển khai và sau đó thực hiện phương thức so sánh:
public int compareTo(Person o) {
int result = name.compareToIgnoreCase(o.name);
if(result==0) {
return Integer.valueOf(age).compareTo(o.age);
}
else {
return result;
}
}
Điều đó sẽ sắp xếp đầu tiên theo tên (trường hợp không nhạy cảm) và sau đó theo tuổi. Sau đó, bạn có thể chạy Arrays.sort()
hoặc Collections.sort()
trên bộ sưu tập hoặc mảng các đối tượng Person.
Quả ổi ComparisonChain
cung cấp một cách làm sạch. Tham khảo liên kết này .
Một tiện ích để thực hiện một tuyên bố so sánh chuỗi. Ví dụ:
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.aString, that.aString)
.compare(this.anInt, that.anInt)
.compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
.result();
}
Sử dụng Comparator
và sau đó đặt các đối tượng vào Collection
, sau đóCollections.sort();
class Person {
String fname;
String lname;
int age;
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public Person(String fname, String lname, int age) {
this.fname = fname;
this.lname = lname;
this.age = age;
}
@Override
public String toString() {
return fname + "," + lname + "," + age;
}
}
public class Main{
public static void main(String[] args) {
List<Person> persons = new java.util.ArrayList<Person>();
persons.add(new Person("abc3", "def3", 10));
persons.add(new Person("abc2", "def2", 32));
persons.add(new Person("abc1", "def1", 65));
persons.add(new Person("abc4", "def4", 10));
System.out.println(persons);
Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person t, Person t1) {
return t.getAge() - t1.getAge();
}
});
System.out.println(persons);
}
}
Tạo càng nhiều bộ so sánh khi cần thiết. Sau đó, gọi phương thức "thenCompared" cho mỗi danh mục đơn hàng. Đó là một cách làm của Streams. Xem:
//Sort by first and last name
System.out.println("\n2.Sort list of person objects by firstName then "
+ "by lastName then by age");
Comparator<Person> sortByFirstName
= (p, o) -> p.firstName.compareToIgnoreCase(o.firstName);
Comparator<Person> sortByLastName
= (p, o) -> p.lastName.compareToIgnoreCase(o.lastName);
Comparator<Person> sortByAge
= (p, o) -> Integer.compare(p.age,o.age);
//Sort by first Name then Sort by last name then sort by age
personList.stream().sorted(
sortByFirstName
.thenComparing(sortByLastName)
.thenComparing(sortByAge)
).forEach(person->
System.out.println(person));
Nhìn: Sắp xếp đối tượng do người dùng xác định trên nhiều trường - Trình so sánh (luồng lambda)
Tôi sẽ cẩn thận khi sử dụng Guava ComparisonChain
vì nó tạo ra một thể hiện của nó cho mỗi phần tử được so sánh để bạn sẽ xem xét việc tạo N x Log N
chuỗi so sánh chỉ để so sánh nếu bạn đang sắp xếp hoặc các N
trường hợp nếu bạn đang lặp lại và kiểm tra sự bằng nhau.
Thay vào đó, tôi sẽ tạo một tĩnh Comparator
bằng cách sử dụng API Java 8 mới nhất nếu có thể hoặc Ordering
API của Guava cho phép bạn làm điều đó, đây là một ví dụ với Java 8:
import java.util.Comparator;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsLast;
private static final Comparator<Person> COMPARATOR = Comparator
.comparing(Person::getName, nullsLast(naturalOrder()))
.thenComparingInt(Person::getAge);
@Override
public int compareTo(@NotNull Person other) {
return COMPARATOR.compare(this, other);
}
Dưới đây là cách sử dụng Ordering
API của Guava : https://github.com/google/guava/wiki/OrderingExplained
compare
phương pháp không tạo ra bất cứ điều gì, nhưng lợi nhuận một trong những trường hợp singleton LESS
, GREATER
hoặc ACTIVE
tùy thuộc vào kết quả của sự so sánh. Đây là một cách tiếp cận được tối ưu hóa cao và không thêm bất kỳ chi phí bộ nhớ hoặc hiệu năng nào.
Hoặc bạn có thể khai thác thực tế là Collections.sort()
(hoặc Arrays.sort()
) ổn định (nó không sắp xếp lại các phần tử bằng nhau) và sử dụng một Comparator
để sắp xếp theo độ tuổi trước và sau đó một phần tử khác để sắp xếp theo tên.
Trong trường hợp cụ thể này, đây không phải là một ý tưởng hay nhưng nếu bạn phải thay đổi thứ tự sắp xếp trong thời gian chạy, nó có thể hữu ích.
Bạn có thể sử dụng Trình so sánh nối tiếp chung để sắp xếp các bộ sưu tập theo nhiều trường.
import org.apache.commons.lang3.reflect.FieldUtils;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @author MaheshRPM
*/
public class SerialComparator<T> implements Comparator<T> {
List<String> sortingFields;
public SerialComparator(List<String> sortingFields) {
this.sortingFields = sortingFields;
}
public SerialComparator(String... sortingFields) {
this.sortingFields = Arrays.asList(sortingFields);
}
@Override
public int compare(T o1, T o2) {
int result = 0;
try {
for (String sortingField : sortingFields) {
if (result == 0) {
Object value1 = FieldUtils.readField(o1, sortingField, true);
Object value2 = FieldUtils.readField(o2, sortingField, true);
if (value1 instanceof Comparable && value2 instanceof Comparable) {
Comparable comparable1 = (Comparable) value1;
Comparable comparable2 = (Comparable) value2;
result = comparable1.compareTo(comparable2);
} else {
throw new RuntimeException("Cannot compare non Comparable fields. " + value1.getClass()
.getName() + " must implement Comparable<" + value1.getClass().getName() + ">");
}
} else {
break;
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return result;
}
}
Arrays.sort(persons, new PersonComparator());
import java.util.Comparator;
public class PersonComparator implements Comparator<? extends Person> {
@Override
public int compare(Person o1, Person o2) {
if(null == o1 || null == o2 || null == o1.getName() || null== o2.getName() ){
throw new NullPointerException();
}else{
int nameComparisonResult = o1.getName().compareTo(o2.getName());
if(0 == nameComparisonResult){
return o1.getAge()-o2.getAge();
}else{
return nameComparisonResult;
}
}
}
}
class Person{
int age; String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Phiên bản cập nhật:
public class PersonComparator implements Comparator<? extends Person> {
@Override
public int compare(Person o1, Person o2) {
int nameComparisonResult = o1.getName().compareToIgnoreCase(o2.getName());
return 0 == nameComparisonResult?o1.getAge()-o2.getAge():nameComparisonResult;
}
}
Đối với một lớp học Book
như thế này:
package books;
public class Book {
private Integer id;
private Integer number;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "book{" +
"id=" + id +
", number=" + number +
", name='" + name + '\'' + '\n' +
'}';
}
}
sắp xếp lớp chính với các đối tượng giả
package books;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
Book b = new Book();
Book c = new Book();
Book d = new Book();
Book e = new Book();
Book f = new Book();
Book g = new Book();
Book g1 = new Book();
Book g2 = new Book();
Book g3 = new Book();
Book g4 = new Book();
b.setId(1);
b.setNumber(12);
b.setName("gk");
c.setId(2);
c.setNumber(12);
c.setName("gk");
d.setId(2);
d.setNumber(13);
d.setName("maths");
e.setId(3);
e.setNumber(3);
e.setName("geometry");
f.setId(3);
f.setNumber(34);
b.setName("gk");
g.setId(3);
g.setNumber(11);
g.setName("gk");
g1.setId(3);
g1.setNumber(88);
g1.setName("gk");
g2.setId(3);
g2.setNumber(91);
g2.setName("gk");
g3.setId(3);
g3.setNumber(101);
g3.setName("gk");
g4.setId(3);
g4.setNumber(4);
g4.setName("gk");
List<Book> allBooks = new ArrayList<Book>();
allBooks.add(b);
allBooks.add(c);
allBooks.add(d);
allBooks.add(e);
allBooks.add(f);
allBooks.add(g);
allBooks.add(g1);
allBooks.add(g2);
allBooks.add(g3);
allBooks.add(g4);
System.out.println(allBooks.size());
Collections.sort(allBooks, new Comparator<Book>() {
@Override
public int compare(Book t, Book t1) {
int a = t.getId()- t1.getId();
if(a == 0){
int a1 = t.getNumber() - t1.getNumber();
return a1;
}
else
return a;
}
});
System.out.println(allBooks);
}
}
Tôi không chắc việc viết người đồng hành bên trong lớp Người trong trường hợp này có xấu không. Đã làm như thế này:
public class Person implements Comparable <Person> {
private String lastName;
private String firstName;
private int age;
public Person(String firstName, String lastName, int BirthDay) {
this.firstName = firstName;
this.lastName = lastName;
this.age = BirthDay;
}
public int getAge() {
return age;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public int compareTo(Person o) {
// default compareTo
}
@Override
public String toString() {
return firstName + " " + lastName + " " + age + "";
}
public static class firstNameComperator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.firstName.compareTo(o2.firstName);
}
}
public static class lastNameComperator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.lastName.compareTo(o2.lastName);
}
}
public static class ageComperator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.age - o2.age;
}
}
}
public class Test {
private static void print() {
ArrayList<Person> list = new ArrayList();
list.add(new Person("Diana", "Agron", 31));
list.add(new Person("Kay", "Panabaker", 27));
list.add(new Person("Lucy", "Hale", 28));
list.add(new Person("Ashley", "Benson", 28));
list.add(new Person("Megan", "Park", 31));
list.add(new Person("Lucas", "Till", 27));
list.add(new Person("Nicholas", "Hoult", 28));
list.add(new Person("Aly", "Michalka", 28));
list.add(new Person("Adam", "Brody", 38));
list.add(new Person("Chris", "Pine", 37));
Collections.sort(list, new Person.lastNameComperator());
Iterator<Person> it = list.iterator();
while(it.hasNext())
System.out.println(it.next().toString());
}
}
Comparator
để tránh phải bỏ các đầu vào.