【问题标题】:Sort a List of objects by multiple fields [duplicate]按多个字段对对象列表进行排序[重复]
【发布时间】:2011-07-27 20:10:06
【问题描述】:

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

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

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

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

【问题讨论】:

  • 该问题的第二个答案就是一个很好的说明。
  • @sim,那你为什么不花时间去理解,而不是去寻找代码呢?
  • @Moonbeam,我的问题文本表明我研究了集合和排序,并且表明我已经在 Stackoverflow 上阅读了其他类似的问题。是什么让你认为我只是在寻找代码?下一次,请不要忽视惠顿定律。
  • @Moonbeam,有时你看代码来理解一个概念。当然是“我的树视图闪烁着可怕的东西!”之类的东西。 “试试这个” “谢谢!”没有帮助任何人学习,但这就是为什么这是 stackOverflow 而不是某个论坛。下课后见。

标签: java sorting collections


【解决方案1】:

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

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),它就会继续比较类的每个连续属性。

【讨论】:

  • 谢谢。你的解释帮助一分钱下跌。现在对 compare() 方法的用法有了更清晰的认识,这是我以前没有的。
  • 不要忘记您的空检查。行'int value1 = o1.campus.compareTo(o2.campus);'如果 o1 为 null,将抛出 NullPointerException
【解决方案2】:

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

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

基本上你是在说,“如果我可以通过查看校园(在他们来自不同的校园之前,校园是最重要的领域)来判断哪个先出现,那么我会返回那个结果。否则,我会继续比较院系。同样,如果这足以区分它们,就停止。否则,(如果两个人的校园和院系相同)只需使用通过构建比较它们的结果。”

【讨论】:

  • 可读性..这应该是正确的答案!
【解决方案3】:

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



    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&lt;City&gt; 是类 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 对象,以及另一个表示ascendant 的字段或后裔

【讨论】:

  • 我一直在寻找的最佳答案 +10
【解决方案4】:

希望对您有所帮助:

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

【讨论】:

    【解决方案5】:

    你只需要让你的类继承自Comparable

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

    【讨论】:

      【解决方案6】:

      您必须编写自己的 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 文档。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-11
        • 2020-04-02
        • 2015-08-08
        • 1970-01-01
        • 1970-01-01
        • 2021-11-05
        • 2015-03-30
        • 2010-10-26
        相关资源
        最近更新 更多