2012-01-31 88 views
2

我写我自己的比较类调用PercentComparator并呼吁排序如下collections.sort定义两个元素的排序顺序?

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

其中engineList为对象的列表,每个对象都有完成百分比值,高于排序功能工作正常。

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

回答

1

如果我猜中了:

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

下面是如何排序的集合:

 

Prod-Type Percent 
======================= 
    A   1 
    A   2 
    A   3 
    B   1 
    B   2 
    B   3 
    C   1 
    C   2 
    C   3 
+0

谢谢你,那个作品,同样的例子也在http://stackoverflow.com/questions/4258700/collections-sort-with-multiple-fields – skalluri 2012-02-01 17:05:00

3

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

+0

我们可以假设Java排序方法是稳定的排序算法吗? – 2012-01-31 20:44:45

+1

Collections.sort是稳定的。从API引用:“例如,排序使用的算法不一定是合并排序,但它必须是**稳定的**。” – msi 2012-01-31 20:47:37

+0

使用番石榴的顺序:'productOrdering.compound(Ordering.from(percentComparator))'依次组合顺序。这可能会稍微方便一些。 (http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Ordering.html) – 2012-01-31 21:57:01

0

如果将要单独分类,请做一个单独的比较器并将它们用于'连锁'。或者做你的EngineComparator(Boolean sortPercentDesc, Boolean sortProductDesc),在我看来这可能会更好,因为会更容易维护。

0

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

0

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

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

0

通常情况下,比较器会一次测试一个字段,直到出现差异。例如,如果%的人服用头等大事,其次是产品类型和你的类有聪明的名称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; 
      }   
    }; 

如果你想一吨的灵活性,通过各种手段写一堆个体比较,并把它们连一起(正如其他人所建议的那样),但很多时候它会过度杀伤 - 你只需要那个。

+0

感谢您的输入,这是一个很好的解决方案,但对于产品类型而言,优先级高于完成百分比,您的文章很有用。 – skalluri 2012-02-01 17:06:45

0

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

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

} 

假设对象是型发动机。

0

对于一个更通用的解决方案,来看看阿帕奇普通的ComparatorChain,来自Javadocs:

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