【问题标题】:collections.sort to define the sort order on two elements?collections.sort 来定义两个元素的排序顺序?
【发布时间】:2012-02-23 14:05:25
【问题描述】:

我正在编写自己的比较器类,名为PercentComparator,并按如下方式调用排序

Collections.sort(engineList, new PercentageComparator());

其中engineList 是对象列表,其中每个对象都有完成百分比值,并且上述排序功能工作正常。

现在客户要求按其产品类型和百分比按元素添加另一个订单。我们可以按对象的两个元素进行排序吗?

【问题讨论】:

    标签: java sorting collections


    【解决方案1】:

    创建您自己的新 Comparator,在比较产品类型后调用 PercentageComparator。

    【讨论】:

    • 我们可以假设Java排序方法是稳定的排序算法吗?
    • Collections.sort 是稳定的。引用自 API:“例如,sort 使用的算法不必是合并排序,但它必须是稳定的。”
    • 使用 Guava 的排序:productOrdering.compound(Ordering.from(percentageComparator)) 依次组合排序。这可能会更方便一些。 (docs.guava-libraries.googlecode.com/git-history/release/javadoc/…)
    • @LouisWasserman 我认为如果允许您使用番石榴,它非常适合这样的东西。我会将其发布为可能的答案。你会得到我的赞成票。干杯。
    • 我可以编辑您的答案以提供一个示例,说明如何在 Guava 中执行此操作吗?我不确定社交协议,但我很乐意用代码编写示例。
    【解决方案2】:

    如果要单独排序,请使用单独的比较器并在“链”中使用它们。或者你的EngineComparator(Boolean sortPercentDesc, Boolean sortProductDesc),在我看来可能会更好,因为更容易维护。

    【讨论】:

      【解决方案3】:

      只要所有相关(可比较的)信息都包含在传递给该方法的对象中,您的排序方法就可以进行任何类型的排序。换句话说,您的可排序对象应该包含所有可排序的子字段。而且你必须编写一个不同的排序方法/类来处理它。

      【讨论】:

        【解决方案4】:

        如果第一个 Comparator 返回 0,您可以创建一个具有两个 Comparator 并返回第二个 Comparator 的值的复合 Comparator。

        您甚至可以使用包含 N 个比较器的列表来扩展此过程并返回第一个非零结果,或者如果到达列表末尾则返回 0

        【讨论】:

          【解决方案5】:

          通常,您的 Comparator 会一次测试一个字段,直到出现差异。例如,如果百分比是最高优先级,其次是产品类型,并且您的类具有巧妙的名称 StackOverflow1:

              Comparator<StackOverflow1> COMPARATOR = new Comparator<StackOverflow1>() {
          
                    @Override
                    public int compare(StackOverflow1 o1, StackOverflow1 o2) {
                       int result = Double.compare(o1.percent, o2.percent);
                       if (result == 0)
                          result = o1.productType - o2.productType;
                          // NOTE - above line isn't really safe but used for illustration...
          
                       // any more tests of fields here...
          
                       return result;
                    }         
             };
          

          如果您想要很大的灵活性,请务必编写一堆单独的比较器并将它们链接在一起(正如其他人所建议的那样),但很多时候它过于矫枉过正 - 您只需要一个。

          【讨论】:

          • 感谢您的输入,这是一个很好的解决方案,但是对于产品类型的优先级高于完成百分比,您的帖子很有用。
          【解决方案6】:

          首先创建另一个仅比较产品类型的比较器实现。然后调用它:

          Collections.sort(engineList, new CompoundComparator(productTypeCmp, percentageCmp));
          

          这是一个复合比较器的实现,它将比较委托给传入的比较器,按照传入的顺序。

          class CompoundComparator implements Comparator<Engine>{ 
              private List<Comparator> comparators;
              public CompoundComparator(Comparator<Engine> ... comparators){
                 this.comparators = Arrays.asList(comparators);
              }
              public int compare(Engine o1, Engine o2){
                 int cmp = 0;
                 Iterator cmpIter = comparators.iterator();
                 while(cmp == 0 && cmpIter.hasNext()){
                    cmp = cmpIter.next().compare(o1, o2);
                 }
                 return cmp;
              }
          
          }
          

          假设对象是引擎类型。

          【讨论】:

            【解决方案7】:
            Collections.sort(engineList, new PercentageComparator());
            Collections.sort(engineList, new ProductTypeComparator());
            

            按产品类型排序,对于相同的产品类型,按百分比进一步排序。这是因为

            这种排序保证稳定:相同的元素不会因为排序而重新排序。

            http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#sort%28java.util.List%29

            【讨论】:

              【解决方案8】:

              如果我猜对了:

              class EngineComparator implements Comparator<Engine> {
                  @Override
                  public int compare(Engine o1, Engine o2) {
                      int result = o1.getProdType().compareTo(o2.getProdType());
                      return (result == 0) ? o1.getPercent().compareTo(o2.getPercent()) : result;
                  }
              }
              

              以下是它对集合的排序方式:

              产品类型百分比 ======================== 1 A2 一个 3 乙 1 乙二 乙 3 C 1 C 2 C 3

              【讨论】:

              【解决方案9】:

              有关更通用的解决方案,请查看 Javadocs 中的 Apache Common 的 ComparatorChain

              ComparatorChain 是一个 Comparator,它依次包装了一个或多个 Comparator。 ComparatorChain 按顺序调用每个 Comparator 直到 1) 任何单个 Comparator 返回非零结果(然后返回该结果),或 2) ComparatorChain 用尽(并返回零)。这种类型的排序与 SQL 中的多列排序非常相似,并且该类允许 Java 类在对 List 进行排序时模拟这种行为。

              【讨论】:

                猜你喜欢
                • 2015-04-21
                • 2017-03-22
                • 1970-01-01
                • 1970-01-01
                • 2013-10-16
                • 1970-01-01
                • 1970-01-01
                • 2019-05-10
                • 1970-01-01
                相关资源
                最近更新 更多