IsaacLevon
IsaacLevon

Reputation: 2570

Java streams with generics

I have a generic function which accepts Collection<? extends T> ts.

I'm also passing:

Function<? extends T, ? extends K> classifier which maps each item T to a key K (possible to have duplicates)

Function<? extends T, Integer> evaluator which gives an integer value for the item.

The function itself has a built-in calculation ("int to int") for every produced Integer (could be something like squaring for our example)

Finally, I'd like to sum all of the values for each key.

So the end result is: Map<K, Integer>.

For example,
Let's say we have the list ["a","a", "bb"] and we use Function.identity to classify, String::length to evaluate and squaring as the built-in function. Then the returned map will be: {"a": 2, "b": 4}

How can I do that? (I guess that preferably using Collectors.groupingBy)

Upvotes: 5

Views: 1587

Answers (2)

Eugene
Eugene

Reputation: 120848

Or another approach:

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));

}

Upvotes: 2

Eran
Eran

Reputation: 393771

Here's one way to do it:

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))));
}

The output for:

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

is

{bb=4, a=2}

Upvotes: 4

Related Questions