Multiobject Comparable / Comparator接口

时间:2015-03-23 00:08:31

标签: java sorting collections java-8 comparator

对于可能需要同时在多个边/对象上进行比较的情况,是否有任何标准接口或方法可用于集合/流(最大值,排序)?

签名可能类似于

  compare(T... toCompare) 

而不是

  compare(T object1, T object2)

我想要的是一个用于比较Java API中的操作的实现。但从我看到的情况来看,我认为我必须强制要求单一的比较。

更新:实际示例:我希望通过Collections / Stream.max()解释比较器实现,这允许我进行多边比较而不是单一比较(即,在比较方法中接受多个T) 。 max函数返回元素,以便元素是比较机制的赢家,自定义实现,与所有其他元素相比,而不是n战1和1的胜者。

UPDATE2:更具体的例子: 我有(Pineapple,Pizza,Yogurt),并且max返回项目,这样我的自定义1 - > n比较返回最大商数。这个商可能像degreeOfYumie。所以菠萝比比萨饼+酸奶更像是yummie,比菠萝+酸奶更像是yummie,而Yogurt与Pizza + Pineapple同样是yummie。所以获胜者是Pineaple。如果我做那个单一的,所有的成分将同样yummie。是否有任何实施比较器的机制/可比较的?也许是一个"可排序的"适用于集合,流和队列的接口?

3 个答案:

答案 0 :(得分:2)

不需要专门的interface。如果您的Comparator符合规范,则它将是可传递的并允许比较多个对象。要获得三个或更多元素的最大值,只需使用,例如

Stream.of(42, 8, 17).max(Comparator.naturalOrder())
      .ifPresent(System.out::println);
// or
Stream.of("foo", "BAR", "Baz").max(String::compareToIgnoreCase)
      .ifPresent(System.out::println);

如果您对max元素的索引感兴趣,可以这样做:

List<String> list=Arrays.asList("foo", "BAR", "z", "Baz");
int index=IntStream.range(0, list.size()).boxed()
  .max(Comparator.comparing(list::get, String.CASE_INSENSITIVE_ORDER))
  .orElseThrow(()->new IllegalStateException("empty list"));

关于您更新的问题...... 您说您希望根据元素属性和其余元素的商来建立排序。让我们通过

来思考

假设我们有正数值abc,并希望根据a/(b+c)b/(a+c)和{{1}建立排序}}

然后我们可以通过扩展商来改变这个词,使其具有一个共同点:

c/(a+b)

由于共同标准对订购没有影响,我们可以忽略它们,在扩展产品后我们得到了条款:

  a(a+c)(a+b)      b(b+c)(b+a)      c(c+b)(c+a)
---------------  ---------------  ---------------
(a+b)(b+c)(a+c)  (a+b)(b+c)(a+c)  (a+b)(b+c)(a+c)

在这里我们可以忽略共同的加法a³+a²b+a²c+abc b³+b²a+b²c+abc c³+c²a+c²b+abc ,因为它对排序没有影响。

abc

然后再次考虑

a³+a²b+a²c       b³+b²a+b²c       c³+c²a+c²b

看到我们有一个可以忽略的共同因素,因为它不会影响排序,所以我们最终得到

a²(a+b+c)        b²(a+b+c)        c²(a+b+c)

这个结果告诉我们什么?只是商数与a² b² c² ab成比例,因此具有相同的排序。因此,当我们能够证明它与基于原始值cab的简单比较器具有相同结果时,不需要实现基于商的比较器。

(如果允许负值,图片会有所不同,但由于允许负值会产生零作为分母的可能性,无论如何它们都不在这个用例中)


应该强调的是,特定比较器的任何其他结果都将证明该比较器不适用于标准c用例。如果所有其他元素的组合值对结果顺序产生影响,换句话说,向关系添加另一个元素将改变排序,如何将操作添加到Comparator或将其插入到排序列表的正确位置有效吗?

答案 1 :(得分:1)

一次比较多个对象的问题是返回什么。 如果第一个对象“小于第二个对象,那么Java比较器返回-1;如果它们是等于,则返回0;如果第一个对象是”更大“,则返回1。

如果比较两个以上的对象,则整数不足以描述所述对象之间的差异。

答案 2 :(得分:1)

如果你有一个正常的Comparable<T>,你可以按照你想要的方式组合它。从能够比较两件事你可以构建任何东西(参见不同的排序算法,通常只需要<实现)。

例如,这里有一个天真的&#34;你可以说它是否比任何一个对象更大,相等或更小&#34;

<T extends Comparable<T>> int compare(T... toCompare) {
    if (toCompare.length < 2) throw Nothing to compare; // or return something
    T first = toCompare[0];
    int smallerCount;
    int equalCount;
    int biggerCount;
    for(int i = 1, n = toCompare.length; i < n; ++i) {
        int compare = first.compareTo(toCompare[i]);
        if(compare == 0) {
            equalCount++;
        } else if(compare < 0) {
            smallerCount++;
        } else {
            biggerCount++;
        }
    }
    return someCombinationOf(smallerCount, equalCount, biggerCount);
}

但是我无法找到合适的方法,(3, 5, 3, 1)小于3的序列5,等于3并且大于1,因此所有计数均为1;在这里你所有的&#34;它比任何&#34;更大,相等或更小。条件同时为真,但如果有助于将计数组合推迟到以后的某个时间点,则可以将计数作为对象返回。