如何在 Java 中实现空操作比较器?
How do I implement a no-op comparator in Java?
假设我有一个接受以下内容的库调用:
- 项目列表(mixed/multiple 类型
T1
、T2
、T3
、..)和
- 自定义比较器
C
,
并且,除了做一些工作之外,还对它接受的列表进行排序(首先按类型,然后使用自定义比较器 C
)。
现在,我需要 T1
类型的项目按 类型 排序,然后使用 自定义顺序 ,而项目所有其他类型(T2
、T3
、..)仅按 type 排序(即,一旦按类型排序,因此仅使用空操作排序,保序比较器)。
换句话说,我需要这样的东西(T1
是java.lang.Integer
,T2
是java.lang.String
):
import java.util.Comparator;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingInt;
class C {
/**
* The library call.
*/
static <T> void processAndSort(final List<T> items,
final Comparator<? super T> secondaryComparator) {
final Comparator<T> typeComparator = comparing(it -> it.getClass().getName());
items.sort(typeComparator.thenComparing(secondaryComparator));
// Do some extra work.
}
public static void main(final String ... args) {
final List<?> items = asList(13, "Lorem",
8, "ipsum",
5, "dolor",
3, "sit",
2, "amet",
1, "consectetur",
1, "adipiscing");
processAndSort(items, (final var left, final var right) -> {
final Class<?> clazz = left.getClass();
/*
* Should be already sorted by type.
*/
if (!clazz.equals(right.getClass())) {
throw new IllegalStateException();
}
if (clazz.equals(Integer.class)) {
/*
* Compare integers using a custom comparator.
*/
return comparingInt(Integer::intValue).compare((Integer) left, (Integer) right);
}
/*
* For all other types, retain the original order.
*/
return 0;
});
System.out.println(items);
}
}
上面的代码,当运行时,会产生如下输出:
[1, 1, 2, 3, 5, 8, 13, Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing]
现在,如果 Merge Sort and Timsort algorithms (used by the JDK to sort non-primitives) are stable,我的自定义比较器是否可以将 return 0 用于应保留顺序的对?
还有其他选择吗?
是的,用这样的Comparator
来排序List
是可以的。
Collections.sort()
(and List.sort()
非常相似的措辞)只需要
All elements in the list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
继续
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.
Comparator
的合同也没有施加任何进一步的限制来禁止这种实施 - 它只是警告说这种顺序不“与平等一致”,因此不能用于某些地图或集合.
是的,但是。
两个重要问题:
是的,比较器有'on equal levels'的概念,意思是:对象在'same hashCode() and a.equals(b)
is true'的意义上可能不一定相等,但比较器表明它们在同级别 (compare(a, b) == 0
)。但是, 意味着什么 取决于使用比较器的东西。具体来说,对于 List.sort,这仅意味着 'at the same level' 的所有内容都将彼此相邻,此外,排序是稳定的,这意味着,无论他们在开始排序之前的顺序如何,都是他们得到的顺序然后。 但这正是 List 排序的作用 - 例如 TreeSet
声明您只能有 1 个这样的元素;如果比较器说 2 个项目在同一级别,就 TreeSet/TreeMap 而言,它们是相等的,因此一个树集中不能有 2 个项目其中 compare(a, b) == 0
,即使 !a.equals(b)
。因此,虽然这个问题的答案是 'yes',但请注意您不能普遍使用 'comparator says they are on the same level'.
比较器报告 compare(a, b) == 0
不等于 a/b 是完全可以接受的,但还有其他规则 not 供辩论。 所有 比较者必须 始终遵守这些规则;不这样做是一个问题,无论您将比较器用于什么目的:
compare(a, a) == 0
必须始终保持。
- 如果
compare(a, b) < 0
,则 compare(b, a) > 0
必须始终成立。
- 如果
compare(a, b) < 0
和compare(b, c) < 0
,则compare(a, c) < 0
必须成立。
这个比较器:
Comparator<Object> communism = (a, b) -> 0;
确实遵守所有这些规则,所以,当然,你可以做到。
假设我有一个接受以下内容的库调用:
- 项目列表(mixed/multiple 类型
T1
、T2
、T3
、..)和 - 自定义比较器
C
,
并且,除了做一些工作之外,还对它接受的列表进行排序(首先按类型,然后使用自定义比较器 C
)。
现在,我需要 T1
类型的项目按 类型 排序,然后使用 自定义顺序 ,而项目所有其他类型(T2
、T3
、..)仅按 type 排序(即,一旦按类型排序,因此仅使用空操作排序,保序比较器)。
换句话说,我需要这样的东西(T1
是java.lang.Integer
,T2
是java.lang.String
):
import java.util.Comparator;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingInt;
class C {
/**
* The library call.
*/
static <T> void processAndSort(final List<T> items,
final Comparator<? super T> secondaryComparator) {
final Comparator<T> typeComparator = comparing(it -> it.getClass().getName());
items.sort(typeComparator.thenComparing(secondaryComparator));
// Do some extra work.
}
public static void main(final String ... args) {
final List<?> items = asList(13, "Lorem",
8, "ipsum",
5, "dolor",
3, "sit",
2, "amet",
1, "consectetur",
1, "adipiscing");
processAndSort(items, (final var left, final var right) -> {
final Class<?> clazz = left.getClass();
/*
* Should be already sorted by type.
*/
if (!clazz.equals(right.getClass())) {
throw new IllegalStateException();
}
if (clazz.equals(Integer.class)) {
/*
* Compare integers using a custom comparator.
*/
return comparingInt(Integer::intValue).compare((Integer) left, (Integer) right);
}
/*
* For all other types, retain the original order.
*/
return 0;
});
System.out.println(items);
}
}
上面的代码,当运行时,会产生如下输出:
[1, 1, 2, 3, 5, 8, 13, Lorem, ipsum, dolor, sit, amet, consectetur, adipiscing]
现在,如果 Merge Sort and Timsort algorithms (used by the JDK to sort non-primitives) are stable,我的自定义比较器是否可以将 return 0 用于应保留顺序的对?
还有其他选择吗?
是的,用这样的Comparator
来排序List
是可以的。
Collections.sort()
(and List.sort()
非常相似的措辞)只需要
All elements in the list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
继续
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.
Comparator
的合同也没有施加任何进一步的限制来禁止这种实施 - 它只是警告说这种顺序不“与平等一致”,因此不能用于某些地图或集合.
是的,但是。
两个重要问题:
是的,比较器有'on equal levels'的概念,意思是:对象在'same hashCode() and
a.equals(b)
is true'的意义上可能不一定相等,但比较器表明它们在同级别 (compare(a, b) == 0
)。但是, 意味着什么 取决于使用比较器的东西。具体来说,对于 List.sort,这仅意味着 'at the same level' 的所有内容都将彼此相邻,此外,排序是稳定的,这意味着,无论他们在开始排序之前的顺序如何,都是他们得到的顺序然后。 但这正是 List 排序的作用 - 例如TreeSet
声明您只能有 1 个这样的元素;如果比较器说 2 个项目在同一级别,就 TreeSet/TreeMap 而言,它们是相等的,因此一个树集中不能有 2 个项目其中compare(a, b) == 0
,即使!a.equals(b)
。因此,虽然这个问题的答案是 'yes',但请注意您不能普遍使用 'comparator says they are on the same level'.比较器报告
compare(a, b) == 0
不等于 a/b 是完全可以接受的,但还有其他规则 not 供辩论。 所有 比较者必须 始终遵守这些规则;不这样做是一个问题,无论您将比较器用于什么目的:
compare(a, a) == 0
必须始终保持。- 如果
compare(a, b) < 0
,则compare(b, a) > 0
必须始终成立。 - 如果
compare(a, b) < 0
和compare(b, c) < 0
,则compare(a, c) < 0
必须成立。
这个比较器:
Comparator<Object> communism = (a, b) -> 0;
确实遵守所有这些规则,所以,当然,你可以做到。