簡體   English   中英

Java 8:慣用於創建Comparator,用於根據List中的索引對對象進行排序

[英]Java 8: Idiomatically creating a Comparator for ordering objects based on their index in a List

在Java 8中創建Comparator<T>實例的最慣用的方法是什么,它根據給定List的相對索引定義對象的排序,但是仍然將該列表中不存在的對象定義為“在”之后的那些對象。在列表中? - 如果我只使用List.indexOf(Object) ,那么不在列表中的對象將始終位於列表中的對象之前 ,因為對於不在列表中的所有對象都返回-1 ,這比任何“true”索引都小:

    final List<String> ordering = Arrays.asList("foo", "bar");
    final Comparator<String> orderingComparator = Comparator.comparingInt(ordering::indexOf);
    final String str1 = "foo";
    final String str2 = "baz";
    final String msg;
    final int cmp = orderingComparator.compare(str1, str2);
    if (cmp < 0) {
        msg = String.format("Element \"%s\" is ordered before \"%s\".", str1, str2);
    } else if (cmp > 0) {
        msg = String.format("Element \"%s\" is ordered after \"%s\".", str1, str2);
    } else {
        msg = String.format("Element \"%s\" is equal to \"%s\".", str1, str2);
    }
    System.out.println(msg);

這打印

元素“foo”在“baz”之后排序。

而我希望的行為會打印出來

元素“foo”在“baz”之前訂購。

您可以將indexOf的結果威脅為無符號整數。 然后-1將是最大值並放在其他值之后。

這可能是最可讀的方法(盡管每個索引都被裝箱):

Comparator.comparing(ordering::indexOf, Integer::compareUnsigned)

這是一個避免裝箱的更快的替代方案:

Comparator.comparingInt(s -> ordering.indexOf(s) + Integer.MIN_VALUE)

我只能想到

    final Comparator<String> orderingComparator 
            = Comparator.comparingInt(s -> ordering.indexOf(s) == -1 ? ordering.size() : ordering.indexOf(s));

現在您的代碼打印:

元素“foo”在“baz”之前訂購。

在這種形式下,它調用indexOf()兩次是低效的。 如果您擔心,我會留給您重寫它以避免這種情況。

PS我將comparing()更改為comparingInt()

提到Integer.compareUnsignedBubletan +1。 如前所述,帶有“下游”比較器的Comparator.comparing的重載僅消耗引用類型,這會導致裝箱開銷。 使用的替代comparingInt避免了開銷,但它意味着你必須做算術的一點點來獲得無符號比較的效果。 另一種方法是為比較器寫出一個lambda,這不是太糟糕。 在這里,它包含在比較器返回函數中:

static <T> Comparator<T> comparingByIndex(List<? extends T> ordering) {
    return (t1, t2) -> Integer.compareUnsigned(ordering.indexOf(t1),
                                               ordering.indexOf(t2));
}

由於Collections.sortStream.sorted提供穩定的排序,因此ordering列表中不存在的元素將以與它們在輸入中出現的順序相同的結尾。 這可能不是你想要的。 如果您希望它們按其他順序排序,那么變體就是提供一個輔助比較器,當兩個元素都不存在時調用它們:

static <T> Comparator<T> comparingByIndex(List<? extends T> ordering,
                                          Comparator<? super T> cmp) {
    return (t1, t2) -> {
        int c1 = ordering.indexOf(t1);
        int c2 = ordering.indexOf(t2);
        if (c1 == -1 && c2 == -1) {
            return cmp.compare(t1, t2);
        } else {
            return Integer.compareUnsigned(c1, c2);
        }
    };
}

如果您要對流進行排序,這些變體可讓您執行以下操作:

    .sorted(comparingByIndex(ordering))

    .sorted(comparingByIndex(ordering, someSpecializedComparator))

    .sorted(comparingByIndex(ordering, Comparator.reverseOrder()))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM