我有一个项目清单(!):
我想将它们分组:
组的定义如下:
问题:是否已准备好执行此操作的API?
<T> List<List<T>> group(Collection<T> collection, BiFunction<T, T, Boolean> eqF);
更新。这个问题完全不是针对可以定义分组质量的情况! 在这种情况下,Java 8 Collectors.groupingBy是最简单的答案。
我正在使用多维向量,并且相等函数如下所示:
对于这种情况,定义哈希值等于解决初始任务:)
最佳答案
您的方案听起来像是groupingBy
收集器的好用例。通常,不提供相等函数,而是提供提取限定符的函数。然后将元素映射到列表中的这些限定符。
即
Map<Qualifier, List<T>> map = list.stream()
.collect(Collectors.groupingBy(T::getQualifier));
Collection<List<T>> result = map.values();
如果
T
的身份是您的限定词,则可以将Function.identity()
用作参数。但是,当您的限定词超过
T
的1个字段时,这将成为一个问题。您可以使用元组类型来创建T
的备用身份,但这仅适用于此,因为每个数量的字段都需要一个单独的元组类。如果要使用
groupingBy
,则确实需要为T
创建一个温和的替代标识,因此不必更改T
的equals
和hashCode
方法。要创建适当的标识,您需要实现
equals
和hashCode
(或始终为哈希码返回0
,但会降低性能)。我不知道有没有为此的API类,但是我做了一个简单的实现:interface AlternateIdentity<T> {
public static <T> Function<T, AlternateIdentity<T>> mapper(
BiPredicate<? super T, Object> equality, ToIntFunction<? super T> hasher) {
return t -> new AlternateIdentity<T>() {
@Override
public boolean equals(Object other) {
return equality.test(t, other);
}
@Override
public int hashCode() {
return hasher.applyAsInt(t);
}
};
}
}
您可以这样使用:
Collection<List<T>> result
= list.stream()
.collect(Collectors.groupingBy(
AlternateIdentity.mapper(eqF, hashF)
))
.values();
其中
eqF
是您的函数,而hashF
是一个哈希代码函数,该函数哈希与eqF
测试相同的字段。 (同样,您也可以只在0
中返回hashF
,但是适当的实现会加快处理速度。)