按多个字段对对象列表进行排序

sim*_*sim 34 java sorting collections

我有一个Java对象列表,我想根据多个字段进行排序.

public class graduationCeremony {
    String campus;
    String faculty;
    String building;
}
Run Code Online (Sandbox Code Playgroud)

是否可以使用a ComparatorComparable界面根据多个字段对列表进行排序?我看到的所有例子都只根据一个字段排序.换句话说,人们可以按"校园"或"教师"或"建筑"进行排序.我想按"校园"排序,然后是"教师",然后是"建筑"(因为它存在于SQL中ORDER BY campus, faculty, building)

我认为之前已经提出过这个问题,但我不明白接受的答案.有人可以扩展或说明这个答案吗?

Dan*_*olo 62

您的比较器看起来像这样:

public class GraduationCeremonyComparator implements Comparator<GraduationCeremony> {
    public int compare(GraduationCeremony o1, GraduationCeremony o2) {
        int value1 = o1.campus.compareTo(o2.campus);
        if (value1 == 0) {
            int value2 = o1.faculty.compareTo(o2.faculty);
            if (value2 == 0) {
                return o1.building.compareTo(o2.building);
            } else {
                return value2;
            }
        }
        return value1;
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,只要到目前为止比较的属性相等(== 0),它就会继续比较类的每个连续属性.


Jon*_*eet 35

是的,你绝对可以做到这一点.例如:

public class PersonComparator implements Comparator<Person>
{
    public int compare(Person p1, Person p2)
    {
        // Assume no nulls, and simple ordinal comparisons

        // First by campus - stop if this gives a result.
        int campusResult = p1.getCampus().compareTo(p2.getCampus());
        if (campusResult != 0)
        {
            return campusResult;
        }

        // Next by faculty
        int facultyResult = p1.getFaculty().compareTo(p2.getFaculty());
        if (facultyResult != 0)
        {
            return facultyResult;
        }

        // Finally by building
        return p1.getBuilding().compareTo(p2.getBuilding());
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上你说的是,"如果我只是通过观察校园(在他们来自不同的校园,校园是最重要的领域之前)来判断哪一个首先出现,那么我只会返回那个结果.否则,我我将继续比较院系.再次,如果这足以告诉他们分开,请停止.否则,(如果校园和教师对两个人都是一样的话),只需使用建筑物比较它们的结果."

  • 可读性..这应该是正确的答案! (2认同)

Mar*_*ley 5

如果您事先知道要使用哪些字段进行比较,那么其他人会给出正确的答案.
您可能感兴趣的是对您的集合进行排序,以防您在编译时不知道应用哪个标准.想象一下,你有一个处理城市的程序:



    protected Set<City> cities;
    (...)
    Field temperatureField = City.class.getDeclaredField("temperature");
    Field numberOfInhabitantsField = City.class.getDeclaredField("numberOfInhabitants");
    Field rainfallField = City.class.getDeclaredField("rainfall");
    program.showCitiesSortBy(temperatureField, numberOfInhabitantsField, rainfallField);
    (...)
    public void showCitiesSortBy(Field... fields) {
        List<City> sortedCities = new ArrayList<City>(cities);
        Collections.sort(sortedCities, new City.CityMultiComparator(fields));
        for (City city : sortedCities) {
            System.out.println(city.toString());
        }
    }
Run Code Online (Sandbox Code Playgroud)

您可以在程序中通过从用户请求中推断出的字段名替换硬编码字段名称.

在这个例子中,City.CityMultiComparator<City>是一个静态嵌套类类的City实现Comparator:



    public static class CityMultiComparator implements Comparator<City> {
        protected List<Field> fields;

        public CityMultiComparator(Field... orderedFields) {
            fields = new ArrayList<Field>();
            for (Field field : orderedFields) {
                fields.add(field);
            }
        }

        @Override
        public int compare(City cityA, City cityB) {
            Integer score = 0;
            Boolean continueComparison = true;
            Iterator itFields = fields.iterator();

            while (itFields.hasNext() && continueComparison) {
                Field field = itFields.next();
                Integer currentScore = 0;
                if (field.getName().equalsIgnoreCase("temperature")) {
                    currentScore = cityA.getTemperature().compareTo(cityB.getTemperature());
                } else if (field.getName().equalsIgnoreCase("numberOfInhabitants")) {
                    currentScore = cityA.getNumberOfInhabitants().compareTo(cityB.getNumberOfInhabitants());
                } else if (field.getName().equalsIgnoreCase("rainfall")) {
                    currentScore = cityA.getRainfall().compareTo(cityB.getRainfall());
                }
                if (currentScore != 0) {
                    continueComparison = false;
                }
                score = currentScore;
            }

            return score;
        }
    }

Run Code Online (Sandbox Code Playgroud)


您可能需要添加额外的精度层,以便为每个字段指定排序是升序还是后代.我想解决方案是用Field你可以调用的类的对象替换对象SortedField,包含一个Field对象,另外一个字段意味着上升后代.