0

I'm dealing with the following POJO:

@Getter
@AllArgsConstructor
public class Order {

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

}

I have a list of this objects and what I'm trying to do is I want to find month (extracted from date field) and category (which is enum type) which has the highest value of quantity. I wanna do it with streams, I made few attempts, but now I'm out of ideas. Could you help me with this?

Below my dummy attempt to resolve this case:

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

Example, we have the following list of data:

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

I want to play with streams and receive the result (e.g some Tuple which contains month, category, quantity).

In the above data-set month with the highest quantity value (9) was February in HEADPHONES category.

5
  • Can you provide an example that can be reproduced? Commented Mar 9, 2019 at 19:36
  • How can result be a Entry<Month, Order> if you need a summed quantity from a combination of Month and Category? Shouldn't result be something like Entry<Pair<Month, Category>, Integer>? Commented Mar 9, 2019 at 19:42
  • @Andronicus Example provided Commented Mar 9, 2019 at 19:50
  • @Andreas It's just my dummy example I didn't want to post a question without making any attempt to resolve it. Commented Mar 9, 2019 at 19:50
  • @KamilW. Before you can write the logic, you need to know what you want the result to be. Otherwise, how can you know you reached the goal, if you don't know what it is? Commented Mar 9, 2019 at 19:59

2 Answers 2

2

You can group by a pair (using SimpleEntry in this example) of the two fields, compute the sum of quantity per group, then stream over the result to pick the entry with the highest value:

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

The output of this with your example data is:

Month: FEBRUARY - Category: HEADPHONES - Quantity: 9
Sign up to request clarification or add additional context in comments.

Comments

1

Here is an example of how to do this with respect to month only (another class can be introduced to compose keys for aggregation):

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

I have separated it into two streams for clarity, but you can join them. First one gives month number with sum of orders, second the greatest month value.

2 Comments

The problem is that OP wants Month / Category combo. Ignoring half the problem prevents this from being a useful answer to the question.
I would change it, but I had the same idea as ernest_k, with another class introduced, so I won't change my answer to avoid duplication and assume it's just a hint on how to do this. But you're right, I forgot about that field, thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.