我有对象数组person (int age;字符串名称;)。

我如何按名字的字母顺序排序这个数组,然后按年龄?

你会用哪种算法呢?


当前回答

当使用Guava的ComparisonChain时,我会很小心,因为它会为每个被比较的元素创建一个实例,所以如果你在排序,你会看到N x Log N个比较链的创建,或者如果你在迭代和检查相等,则会有N个实例。

如果可能的话,我会使用最新的Java 8 API或Guava的ordered API创建一个静态比较器,这里是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);
}

以下是如何使用番石榴的订购API: https://github.com/google/guava/wiki/OrderingExplained

其他回答

我不确定在Person类中写比较器是否丑陋。是这样的:

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()); 
     }  
}    

你可以这样做:

List<User> users = Lists.newArrayList(
  new User("Pedro", 12), 
  new User("Maria", 10), 
  new User("Rafael",12)
);

users.sort(
  Comparator.comparing(User::getName).thenComparing(User::getAge)
);

让你的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()。

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();
   }

对于那些能够使用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);
    }
}