Потоки Java с дженериками

У меня есть общая функция, которая принимает Collection<? extends T> ts.

Я также прохожу:

Function<? extends T, ? extends K> classifier который сопоставляет каждый элемент T с ключом K (возможны дубликаты)

Function<? extends T, Integer> evaluator что дает целочисленное значение элемента.

Сама функция имеет вычисление встроенный ("int to int") для каждого произведенного Integer (может быть что-то вроде возведения в квадрат для нашего примера)

Наконец, я хотел бы суммировать все значения для каждого ключа.

Итак, конечный результат: Map<K, Integer>.

Например,
Допустим, у нас есть список ["a","a", "bb"], и мы используем Function.identity для классификации, String::length для оценки и возведения в квадрат как встроенную функцию. Тогда возвращенная карта будет: {"a": 2, "b": 4}

Как я могу это сделать? (Я предполагаю, что предпочтительно использовать Collectors.groupingBy)

Потому что мы тоже в квадрате

yaseco 01.04.2019 09:37

К чему привели ваши поиски и исследования? Вы пробовали что-то?

Ole V.V. 01.04.2019 09:43

@OleV.V., да, действительно пытался интегрировать его с Collectors.groupingBy. это не сработало

yaseco 01.04.2019 09:45

@yaseco Покажи, а не рассказывай.

Michael 01.04.2019 09:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
4
1 047
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот один из способов сделать это:

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}

Большое спасибо Эран! (Видимо, я был очень близок к ответу, но вы закрыли для меня пробел - Ура!)

yaseco 01.04.2019 10:18

Мне нужно лучше понять часть downstream

yaseco 01.04.2019 10:19

@yaseco Collectors.summingInt() позволяет сопоставить каждый из T элементов данной группы с целым числом, а затем суммировать все эти целые числа. t->evaluator.andThen(calculator).apply(t) берет экземпляр T, применяет к нему функцию evaluator, а затем применяет функцию calculator к результату.

Eran 01.04.2019 10:23
t->evaluator.andThen(calculator).apply(t) будет неоднократно вызывать andThen, создавая новый экземпляр Function для каждой оценки этого лямбда-выражения. Прямой способ применить метод к результату другого — это вложенный вызов, например t -> calculator.apply(evaluator.apply(t)). Или, если это действительно должна быть новая функциональная конструкция, evaluator.andThen(calculator)::apply вызовет andThen только один раз и зафиксирует результат.
Holger 01.04.2019 11:12

Или другой подход:

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

}

И используйте его с:

public static void main(String[] args) {

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

}

Забавно, как далеко люди заходят, просто используя ссылки на методы. Здесь с помощью evaluator::apply и andThen::apply можно преобразовать Function в Function. Поскольку это уже экземпляры Function, подойдет простой Collectors.mapping(evaluator, Collectors.mapping(andThen, …)), и как только вы поймете, что ни лямбда-выражение, ни ссылка на метод не требуются, вы можете использовать один комбинированный Collectors.mapping(evaluator.andThen(andThen), …), в отличие от другого ответа, это не будет повторно вызывать andThen

Holger 01.04.2019 11:06

Другие вопросы по теме