Java泛型流

5
我有一个通用函数,可以接受Collection<? extends T> ts
我还传递了: Function<? extends T, ? extends K> classifier映射每个项目T到一个键K(可能会有重复) Function<? extends T, Integer> evaluator为项目提供一个整数值。
该函数本身具有每个生成的Integer(例如平方)的内置计算"int to int"。
最后,我想对每个键总和所有值。
因此最终结果是:Map<K, Integer>
例如,
假设我们有列表["a","a", "bb"],并使用Function.identity进行分类,使用String::length进行评估,并将平方作为内置函数。然后返回的地图将是:{"a": 2, "b": 4} 怎么做呢?(我猜最好使用Collectors.groupingBy)

因为我们也在进行平方运算。 - IsaacLevon
1
你的搜索和研究有什么结果?你尝试过什么吗? - Ole V.V.
@OleV.V.,是的,我确实尝试将其与Collectors.groupingBy集成。但是没有成功。 - IsaacLevon
2
@yaseco 展示,不要讲。 - Michael
2个回答

4

以下是一种实现方法:

public static <T,K> Map<K,Integer> mapper (
    Collection<T> ts,
    Function<T, K> classifier,
    Function<T, Integer> evaluator,
    Function<Integer,Integer> calculator) 
{
     return
        ts.stream()
          .collect(Collectors.groupingBy(classifier,
                                         Collectors.summingInt(t->evaluator.andThen(calculator).apply(t))));
}

针对以下输入的输出:

System.out.println (mapper(Arrays.asList("a","a","bb"),Function.identity(),String::length,i->i*i));

{bb=4, a=2}

非常感谢你,Eran!(显然,我离答案很近,但你帮我填补了空白 - 干杯!) - IsaacLevon
我确实需要更好地理解“下游”部分。 - IsaacLevon
1
@yaseco Collectors.summingInt() 允许您将给定组的每个 T 元素映射到 int,然后对所有这些 int 进行求和。t->evaluator.andThen(calculator).apply(t) 接受一个 T 实例,对其应用 evaluator 函数,然后对结果应用 calculator 函数。 - Eran
4
t->evaluator.andThen(calculator).apply(t) 将重复调用 andThen 方法,每次对该 lambda 表达式进行求值都会构造一个新的函数实例。将一个方法应用于另一个方法的结果的简单方法是像 t -> calculator.apply(evaluator.apply(t)) 这样嵌套调用。或者,如果真的需要一个新的函数式构造,则 evaluator.andThen(calculator)::apply 将仅调用一次 andThen 并捕获结果。 - Holger

2
另一种方法是:

或者采用另一种方法:

private static <K, T> Map<K, Integer> map(Collection<? extends T> ts,
                                          Function<? super T, ? extends K> classifier,
                                          Function<? super T, Integer> evaluator,
                                          Function<Integer, Integer> andThen) {

    return ts.stream()
             .collect(Collectors.groupingBy(
                 classifier,
                 Collectors.mapping(evaluator.andThen(andThen),
                                    Collectors.reducing(0, Integer::sum))
             ));

}

And use it with:

public static void main(String[] args) {

    System.out.println(map(
        Arrays.asList("a", "a", "bb"),
        Function.identity(),
        String::length,
        x -> x * x));

}

1
有趣的是,人们会走很远的路,只是为了使用方法引用。在这里,使用 evaluator::applyandThen::applyFunction 转换为 Function。由于它们已经是 Function 实例,简单的 Collectors.mapping(evaluator, Collectors.mapping(andThen, ...)) 就可以了。一旦你意识到不需要 lambda 表达式或方法引用,你就可以使用一个组合的 Collectors.mapping(evaluator.andThen(andThen), ...),与其他答案不同,这不会重复调用 andThen... - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接