今天生成word文档时,遇到了集合中多个字段按拼音排序的问题,好久没有写过比较器了,顺带着温习一下。

问题

有一个对象集合,集合中有一些字符串类型的字段,要根据拼音顺序进行排序,该如何实现?

模拟

有一个对象类 Person,具有四个字段:name、age、height 和 weight,现在我们要对一个存储了多个 Person 对象的集合进行排序。我们将按照以下规则排序:首先按照 age 升序排序,然后按照 height 降序排序,接着按照 weight 升序排序,最后按照 name 字母顺序排序。

public class Person {
    private String name;
    private int age;
    private double height;
    private double weight;

    // 构造函数、getter 和 setter 方法省略

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                '}';
    }
}

方式1:自定义比较器

import java.util.Comparator;

public class PersonComparator implements Comparator<Person> {

    @Override
    public int compare(Person p1, Person p2) {
        int result = p1.getName().compareTo(p2.getName());
        if (result == 0) {
            result = Double.compare(p2.getHeight(), p1.getHeight());
            if (result == 0) {
                result = Double.compare(p1.getWeight(), p2.getWeight());
                if (result == 0) {
                    result = Integer.compare(p1.getAge(), p2.getAge());
                }
            }
        }
        return result;
    }
}
测试方法:
public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("阿里", 30, 170.5, 60.0));
        personList.add(new Person("美星", 25, 165.0, 70.0));
        personList.add(new Person("腾讯", 30, 180.0, 80.0));

        // 使用自定义比较器进行排序
        Collections.sort(personList, new PersonComparator());

        // 输出排序后的结果
        for (Person person : personList) {
            System.out.println(person);
        }  
    }
输出结果:
Person{name='美星', age=25, height=165.0, weight=70.0}
Person{name='腾讯', age=30, height=180.0, weight=80.0}
Person{name='阿里', age=30, height=170.5, weight=60.0}

阿里按拼音来排序,肯定是排在第一个,这样是不对的?

改善比较器:
import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;

public class PersonComparator implements Comparator<Person> {
    //定义排列规则,根据汉语拼音进行排序
    private Collator collator = Collator.getInstance(Locale.CHINA);

    @Override
    public int compare(Person p1, Person p2) {
        int result = collator.compare(p1.getName(), p2.getName());
        if (result == 0) {
            result = Double.compare(p2.getHeight(), p1.getHeight());
            if (result == 0) {
                result = Double.compare(p1.getWeight(), p2.getWeight());
                if (result == 0) {
                    result = Integer.compare(p1.getAge(), p2.getAge());
                }
            }
        }
        return result;
    }
}

输出结果:

Person{name='阿里', age=30, height=170.5, weight=60.0}
Person{name='美星', age=25, height=165.0, weight=70.0}
Person{name='腾讯', age=30, height=180.0, weight=80.0}

这样就没有问题啦!

方式2:使用 Comparator.comparing 方法:

样例
public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("张三", 30, 170.5, 60.0));
        personList.add(new Person("李四", 25, 165.0, 70.0));
        personList.add(new Person("王五", 30, 180.0, 80.0));

        // 使用 Comparator.comparing 方法结合 Collator 进行排序
        Collator collator = Collator.getInstance(Locale.CHINA);
        personList.sort(
            Comparator.comparing((Person p) -> p.getName(), collator)
                      .thenComparing(Person::getAge)
                      .thenComparing(Person::getHeight, Comparator.reverseOrder())
                      .thenComparing(Person::getWeight)
        );

        // 输出排序后的结果
        for (Person person : personList) {
            System.out.println(person);
        }
    }

这样写起来,更加简洁。

输出结果:

Person{name='李四', age=25, height=165.0, weight=70.0}
Person{name='王五', age=30, height=180.0, weight=80.0}
Person{name='张三', age=30, height=170.5, weight=60.0}

问题已解决,今天先到这。

晚安!