多对象Comparable/Comparator 接口

Multiobject Comparable/Comparator interface

对于可能需要同时比较多个 sides/objects 的情况,collections/streams(最大值,排序)中是否有可用的标准接口或方法?

签名可能类似于

  compare(T... toCompare) 

而不是

  compare(T object1, T object2)

我想要的是做一个用于比较 Java API 中的操作的实现。但据我所见,我认为我必须坚持强制比较。

更新:实际示例:我希望有一个由 Collections/Stream.max() 解释的 Comparator 实现,它允许我进行多边比较而不是单一比较(即在比较中接受多个 T方法)。 max 函数 returns 元素,因此该元素是比较机制的赢家,自定义实现,它与所有其他人相比,而不是 n 场战斗 1 对 1 的赢家。

更新 2:更具体的例子: 我有(菠萝、披萨、酸奶)和最大 returns 项,这样我的自定义 1 -> n 比较 returns 最大商。这个商数可能类似于 degreeOfYumie。所以菠萝比披萨+酸奶更美味,比萨比菠萝+酸奶更美味,酸奶比披萨+菠萝同样美味。所以赢家是菠萝。如果我做那个单一的,所有的成分都会同样美味。是否有任何机制可以像那样实现 comparator/comparable ?也许 "sortable" 接口适用于集合、流和队列?

一次比较多个对象的问题是return。 Java 比较器 returns -1 如果第一个对象 "smaller than the second one, 0 if they are equals and 1 if the first one is the " 更大”。

如果您比较两个以上的对象,一个整数不足以描述这些对象之间的差异。

如果你有一个普通的Comparable<T>,你可以随意组合它。通过比较两件事,你可以构建任何东西(参见不同的排序算法,通常只需要 < 实现)。

例如,这是 "you could say if it's bigger, equal or smaller than ANY of the objects"

的一个天真的例子
<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;这里所有 "it's bigger, equal or smaller than ANY" 条件同时为真,但是如果有助于将计数组合推迟到稍后的时间点,您可以 return 将计数作为一个对象。

不需要专门的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)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²

这个结果告诉我们什么?简单地说,商与值 abc 成正比,因此具有 相同的顺序 。因此,当我们可以证明它与基于原始值 abc.[= 的简单比较器具有相同结果时,就没有必要实施基于商的比较器了。 34=]

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


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