在Java 8中创建Comparator<T>
实例的最惯用的方法是什么,它根据给定List
中的相对索引定义对象的排序,但仍然定义了该列表中不存在的对象作为&#34;之后&#34;列表中 的那些? - 如果我只使用List.indexOf(Object)
,则列表中不包含的对象 之前的,因为对于不在列表中的所有对象返回-1
这一事实,这比任何&#34;真&#34;指数:
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);
打印
元素&#34; foo&#34;是在&#34; baz&#34;。
之后订购的
而我想要的行为会打印
元素&#34; foo&#34;在&#34; baz&#34;。
之前订购
答案 0 :(得分:9)
您可以将indexOf
的结果威胁为无符号整数。然后-1
将是最大值并放在其他值之后。
这可能是最易读的方法(虽然每个索引都装箱了):
Comparator.comparing(ordering::indexOf, Integer::compareUnsigned)
这是一个避免装箱的更快的替代方案:
Comparator.comparingInt(s -> ordering.indexOf(s) + Integer.MIN_VALUE)
答案 1 :(得分:4)
我只能想到
final Comparator<String> orderingComparator
= Comparator.comparingInt(s -> ordering.indexOf(s) == -1 ? ordering.size() : ordering.indexOf(s));
现在你的代码打印出来了:
元素“foo”在“baz”之前订购。
在这种形式下,它调用indexOf()
两次是低效的。如果你担心,我会留给你重写它以避免这种情况。
PS我将comparing()
更改为comparingInt()
。
答案 2 :(得分:2)
+1到Bubletan提及Integer.compareUnsigned
。如前所述,Comparator.comparing
的过载需要&#34;下游&#34;比较器仅消耗引用类型,这会导致拳击开销。使用comparingInt
的替代方法可以避免这种开销,但这意味着您必须执行一些算术来获得无符号比较的效果。另一种方法是为比较器写出一个lambda,这不是太糟糕。在这里,它包含在比较器返回函数中:
static <T> Comparator<T> comparingByIndex(List<? extends T> ordering) {
return (t1, t2) -> Integer.compareUnsigned(ordering.indexOf(t1),
ordering.indexOf(t2));
}
由于Collections.sort
和Stream.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()))