对多个字段进行排序

时间:2011-08-20 00:23:05

标签: java sorting arraylist

我首先尝试按 car make 排序,然后按汽车年度排序,然后按汽车里程排序。所有字段都是字符串。

这是我到目前为止所尝试的内容:

class Sorter implements Comparator<Car> {
  @Override
  public int compare(Car o1, Car o2) {
    if(o1.getMake().compareToIgnoreCase(o2.getMake()) == 0 && Integer.parseInt(o1.getYear()) != Integer.parseInt(o2.getYear())){
      if(Integer.parseInt(o1.getYear()) > Integer.parseInt(o2.getYear())){
        return -1;
      }else{
        return 1;
      }
    }
    if(o1.getMake().compareToIgnoreCase(o2.getMake()) == 0 && Integer.parseInt(o1.getYear()) == Integer.parseInt(o2.getYear())){
      if(Integer.parseInt(o1.getMileage()) > Integer.parseInt(o2.getMileage())){
        return 1;
      }else{
        return -1;
      }
    }
    return o1.getMake().compareToIgnoreCase(o2.getMake());

  }
}

我正在尝试构建一个类似于excel的算法,您可以按一列然后另一列然后另一列进行排序。

5 个答案:

答案 0 :(得分:1)

一般方法称为lexicographic ordering,这是我们用来对单词进行排序的方法。假设我们要按字段Cf1 ... f2对类fn的两个对象进行排序,我们按以下步骤操作:

  1. 比较两个f1字段;如果它们不同,则比较结果是最终结果,否则
  2. 对以下每个字段重复此操作。
  3. 在代码中(注意 - 未编译):

    class Sorter implements Comparator<Car> {
      @Override
      public int compare(Car o1, Car o2) {
        int res = o1.getMake().compareToIgnoreCase(o2.getMake());
        if ( res != 0 )
          return res;
        res = o1.getYear().compareTo(o2.getYear());
        if ( res != 0 )
          return res;
        return Integer.parseInt(o1.getMileage()).compareTo(Integer.parseInt(o2.getMileage()));
      }
    }
    

答案 1 :(得分:1)

  

如果某个类有多个重要字段,那么您的顺序   比较它们是至关重要的你必须从最重要的开始   领域和工作你的方式。如果比较产生任何结果   除了零(代表平等)之外,你已经完成了;回来吧   结果。如果最重要的字段相等,则继续比较   下一个最重要的字段,依此类推。如果所有字段都相等,   对象是平等的;返回零..(有效的Java)。

public int compare(Car car1, Car car2) {
    // compare make 
    int makeDiff = car1.getMake().compare(car2.getMake());
    if ( makeDiff != 0 )
        return makeDiff;

    // compare year
    int yearDiff = car1.getYear().compare(car2.getYear());
    if ( yearDiff != 0 )
        return yearDiff;

    // compare mileage
    int mileageDiff = car1.getMileage().compare(car2.getMileage());
    if ( mileageDiff != 0 )
        return mileageDiff;

    return 0;
}

答案 2 :(得分:0)

我会写一个MultiComparator,如下所示:

class MultiComparator<T> implements Comparator<T> {
  private final List<Comparator<T>> comparators = new ArrayList<Comparator<T>>();
  public MultiComparator(final List<Comparator<T>> comps) { ... }
  @Override int compareTo(T t1, T t2) {
    for (Comparator<T> c: comparators) {
      int d = c.compareTo(t1, t2);
      if (d != 0) return d;
    }
    return 0;
  }
}

然后用3个独立的比较器实例化MultiComparator<T>,每个比较器只比较你说的一个字段。然后你会得到你想要的结果。

答案 3 :(得分:0)

  

我试图先按汽车制造排序然后按汽车年排序然后排序   乘车里程。所有字段都是字符串。

A)你应该改变你的设计。年份应为int,里程数应为int,float或由其中一个和一个单元组成的对象。字符串不是正确的表示。此外,如果您在比较器中使用它们,则每次比较至少需要将它们转换为适当的类型,这非常低效,

b)为了实现比较器,您可能想要使用外部库。 Guava和Commons / Lang都非常擅长。在下面的例子中,我假设Year和Mileage都是数字。

GuavaComparisonChain):

public int compare(Car o1, Car o2) {
    return ComparisonChain.start()
       .compare(o1.getYear(), o2.getYear())
       .compare(o1.getMileage(), o2.getMileage())
       .compare(o1.getMake(), o2.getMake())
       .getResult();
}

Commons / LangCompareToBuilder):

public int compare(Car o1, Car o2) {
    return new CompareToBuilder()
       .append(o1.getYear(), o2.getYear())
       .append(o1.getMileage(), o2.getMileage())
       .append(o1.getMake(), o2.getMake())
       .toComparison();
}

正如您所看到的,两个版本非常相似,而且比您自己编码要容易得多。

答案 4 :(得分:0)

查看Apache Commons Collection中的ComparatorChain 在以下网站上,我有一个教程:Sorting Objects By Multiple Attributes