我有对象数组person (int age;字符串名称;)。
我如何按名字的字母顺序排序这个数组,然后按年龄?
你会用哪种算法呢?
我有对象数组person (int age;字符串名称;)。
我如何按名字的字母顺序排序这个数组,然后按年龄?
你会用哪种算法呢?
当前回答
Guava的ComparisonChain提供了一种干净的方法。参考这个链接。
用于执行链式比较语句的实用程序。例如:
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();
}
其他回答
您需要实现自己的Comparator,然后使用它:例如
Arrays.sort(persons, new PersonComparator());
你的比较器可以看起来像这样:
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));
}
}
}
比较程序首先比较两个名字,如果它们不相等,就返回比较结果,否则就返回比较两人年龄时的比较结果。
这段代码只是一个草稿:因为这个类是不可变的,你可以考虑为它构建一个单例,而不是为每次排序创建一个新实例。
您可以使用通用串行比较器按多个字段对集合进行排序。
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;
}
}
根据需要创建尽可能多的比较器。之后,为每个订单类别调用“then comparison”方法。这是Streams的一种做法。看到的:
//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));
在多个字段上对用户定义的对象进行排序- Comparator (lambda stream)
对于那些能够使用Java 8流API的人来说,这里有一个更整洁的方法: lambda和排序
我正在寻找相当于c# LINQ:
.ThenBy(...)
我在Comparator上找到了Java 8的机制:
.thenComparing(...)
下面是演示算法的代码片段。
Comparator<Person> comparator = Comparator.comparing(person -> person.name);
comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
请查看上面的链接,以获得更简洁的方法,并解释Java的类型推断如何使其与LINQ相比定义起来更笨拙。
下面是完整的单元测试供参考:
@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);
}
}
让你的person类实现Comparable< person >,然后实现compareTo方法,例如:
public int compareTo(Person o) {
int result = name.compareToIgnoreCase(o.name);
if(result==0) {
return Integer.valueOf(age).compareTo(o.age);
}
else {
return result;
}
}
它将首先按名称(大小写不敏感)排序,然后按年龄排序。然后可以在Person对象的集合或数组上运行Arrays.sort()或Collections.sort()。