Java Strems - Извлечение вложенного объекта и группы - PullRequest
0 голосов
/ 09 марта 2019

Я имею дело со следующим POJO:

@Getter
@AllArgsConstructor
public class Order {

  private int quantity;
  private Category category;
  private LocalDate date;
  //rest fields

}

У меня есть список этих объектов, и я пытаюсь найти месяц, который я хочу найти (извлечено из поля date)и категория (которая является типом enum), которая имеет наибольшее значение quantity.Я хочу сделать это с потоками, я сделал несколько попыток, но теперь у меня нет идей.Не могли бы вы помочь мне с этим?

Ниже моей фиктивной попытки разрешить это дело:

   Optional<Entry<Month, Order>> result = orders.stream()
        .collect(
            Collectors.groupingBy(Order::getLocalDate, Collectors.maxBy(Comparator.comparingInt(Order::getQuantity))))
        .entrySet()
        .stream()
        .collect(Collectors.toMap(e -> e.getKey().getMonth(), e -> e.getValue().get()))
        .entrySet()
        .stream()
        .max(Entry.comparingByValue(Comparator.comparingInt(Order::getQuantity)));

Например, у нас есть следующий список данных:

List<Order> orders = Arrays.asList(
    new Order(Category.HEADPHONES,3, LocalDate.of(2018, 2, 22)),
    new Order(Category.HEADPHONES,6, LocalDate.of(2018, 2, 23)),
    new Order(Category.NOTEBOOKS,8, LocalDate.of(2018, 2, 24)),
    new Order(Category.NOTEBOOKS,4, LocalDate.of(2018, 3, 3)),
    new Order(Category.NOTEBOOKS,1, LocalDate.of(2018, 3, 3)),
    new Order(Category.PHONES,2, LocalDate.of(2018, 3,5)),
    new Order(Category.PHONES,2, LocalDate.of(2018, 3,7))
);

Я хочу поиграть с потоками и получить результат (например, некоторый кортеж, содержащий month, category, quantity).

В указанном выше месяце набора данных с наибольшим значением количества (9) было February в категории HEADPHONES.

Ответы [ 2 ]

2 голосов
/ 09 марта 2019

Вы можете сгруппировать по паре (используя SimpleEntry в этом примере) из двух полей, вычислить сумму количества по группе, а затем перенаправить результат, чтобы выбрать запись с наибольшим значением:

orders.stream()
    .collect(Collectors.groupingBy(
                o -> new SimpleEntry<>(o.getDate().getMonth(), o.getCategory()),
                Collectors.summingInt(Order::getQuantity)))
    .entrySet()
    .stream()
    .max(Entry.comparingByValue())
    .ifPresent(cat -> System.out.println(
                "Month: " + cat.getKey().getKey() + 
                " - Category: " + cat.getKey().getValue() + 
                " - Quantity: " + cat.getValue()));

Вывод этого с данными вашего примера:

Month: FEBRUARY - Category: HEADPHONES - Quantity: 9
1 голос
/ 09 марта 2019

Вот пример того, как сделать это только в отношении месяца (можно ввести другой класс для составления ключей для агрегации):

// month, sum
Map<Integer, Integer> map = orders.stream()
        .collect(groupingBy(o -> o.getDate().getMonthValue(), TreeMap::new, summingInt(Order::getQuantity)));

int month = map.entrySet().stream().reduce((s1, s2) -> {
    if (s1.getValue() > s2.getValue()) return s1;
    else return s2;
}).get().getKey();

Для ясности я разделил его на два потока, ноВы можете присоединиться к ним.Первый дает номер месяца с суммой заказов, второй - наибольшее значение месяца.

...