我有一个项目清单(!):

  • B
  • C
  • D
  • E
  • ...

  • 我想将它们分组:
  • [A,C,D]
  • [B,E]
  • ...

  • 组的定义如下:
  • 根据自定义函数f(a,b)-> boolean
  • ,组中的所有项目均相等
  • f(a,b)= f(b,a)

  • 问题:是否已准备好执行此操作的API?
    <T> List<List<T>> group(Collection<T> collection, BiFunction<T, T, Boolean> eqF);
    

    更新。这个问题完全不是针对可以定义分组质量的情况! 在这种情况下,Java 8 Collectors.groupingBy是最简单的答案。

    我正在使用多维向量,并且相等函数如下所示:
  • 指标(a,b)
    对于这种情况,定义哈希值等于解决初始任务:)

    最佳答案

    您的方案听起来像是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创建一个温和的替代标识,因此不必更改TequalshashCode方法。

    要创建适当的标识,您需要实现equalshashCode(或始终为哈希码返回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,但是适当的实现会加快处理速度。)

  • 10-07 15:12