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

时间:2011-07-27 20:10:06

标签: java sorting collections

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

public class graduationCeremony {
    String campus;
    String faculty;
    String building;
}

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

我认为这个问题已经asked before,但我不明白接受的答案。有人可以扩展或说明这个答案吗?

6 个答案:

答案 0 :(得分:60)

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

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

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

答案 1 :(得分:34)

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

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

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

答案 2 :(得分: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());
        }
    }

您可以使用从程序中的用户请求推断的字段名替换硬编码的字段名称。

在此示例中,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;
        }
    }


您可能希望添加额外的精度层,以便为每个字段指定排序是升序还是后代。我想一个解决方案是用可以调用 Field 的类的对象替换SortedField个对象,其中包含Field个对象,另外还有另一个字段,意思是方兴未艾后代

答案 3 :(得分:1)

希望这有助于:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

class Person implements Comparable {
  String firstName, lastName;

  public Person(String f, String l) {
    this.firstName = f;
    this.lastName = l;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public String toString() {
    return "[ firstname=" + firstName + ",lastname=" + lastName + "]";
  }

  public int compareTo(Object obj) {
    Person emp = (Person) obj;
    int deptComp = firstName.compareTo(emp.getFirstName());

    return ((deptComp == 0) ? lastName.compareTo(emp.getLastName()) : deptComp);
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person emp = (Person) obj;
    return firstName.equals(emp.getFirstName()) && lastName.equals(emp.getLastName());
  }
}

class PersonComparator implements Comparator<Person> {
  public int compare(Person emp1, Person emp2) {
    int nameComp = emp1.getLastName().compareTo(emp2.getLastName());
    return ((nameComp == 0) ? emp1.getFirstName().compareTo(emp2.getFirstName()) : nameComp);
  }
}

public class Main {
  public static void main(String args[]) {
    ArrayList<Person> names = new ArrayList<Person>();
    names.add(new Person("E", "T"));
    names.add(new Person("A", "G"));
    names.add(new Person("B", "H"));
    names.add(new Person("C", "J"));

    Iterator iter1 = names.iterator();
    while (iter1.hasNext()) {
      System.out.println(iter1.next());
    }
    Collections.sort(names, new PersonComparator());
    Iterator iter2 = names.iterator();
    while (iter2.hasNext()) {
      System.out.println(iter2.next());
    }
  }
}

答案 4 :(得分:1)

您只需要让您的班级继承自Comparable

然后按照您喜欢的方式实现compareTo方法。

答案 5 :(得分:0)

您必须编写自己的compareTo()方法,该方法具有执行比较所需的Java代码。

如果我们想比较两个公共领域,校园,然后是教师,我们可能会做类似的事情:

int compareTo(GraduationCeremony gc)
{
    int c = this.campus.compareTo(gc.campus);

    if( c != 0 )
    {
        //sort by campus if we can
        return c;
    }
    else
    {
        //campus equal, so sort by faculty
        return this.faculty.compareTo(gc.faculty);
    }
}

这是简化的,但希望能给你一个想法。有关详细信息,请参阅Comparable和Comparator文档。