3

I have this problem that I need to solve using Java 8 streams, but so far I have not succeeded.

I have:

public class Customer {
 String id;
 String firstName;
 String lastName;
}
public class Order {
 private final String id;
 Set<OrderLine> orderLines = new HashSet<>();
 Customer customer;
}
public class OrderLine {
 Product product;
 Integer quantity;
}
public class Product {
 String name;
 BigDecimal price;
}

All objects have their own equals implemented so its possible to compare objects.

This is the data that i have to iterate from:

 List<Order> orders = new ArrayList<>();
 Customer customer1 = new Customer(randomId(), "Will", "Sanders");
 Customer customer2 = new Customer(randomId(), "Jonh", "Doe");
 Product p1 = new Product("Book 1", new BigDecimal("50.00"));
 Product p2 = new Product("Book 2", new BigDecimal("19.00"));
 Product p3 = new Product("Book 3", new BigDecimal("100.00"));
 orders.add(new Order(randomId(), customer1).addOrderLine(p1, 1));
 orders.add(new Order(randomId(), customer1).addOrderLine(p2, 1));
 orders.add(new Order(randomId(), customer2).addOrderLine(p3, 1));

And i want to know which customer has given more money to the company.

I have solved this using a foreach like this:

 orders.forEach(order -> {
 
 order.getOrderLines().forEach(orderLine -> { 
 
 if(!map.containsKey(order.getCustomer())) {
 map.put(order.getCustomer(), orderLine.getProduct().getPrice());
 } else {
 map.put(order.getCustomer(),map.get(order.getCustomer()).add(orderLine.getProduct().getPrice()));
 }
 });
 });
 
 Customer c = Collections.max(map.entrySet(), Comparator.comparing(Map.Entry::getValue)).getKey();

but i would like to know a way to solve this with streams.

My first thought was transforming this a Map<Customer,BigDecimal>, where that BigDecimal value would be the sum of all customer purchases.

Any Sugestions?

Thanks.

ETO
7,3271 gold badge22 silver badges40 bronze badges
asked Mar 9, 2021 at 10:06

1 Answer 1

4

Let's do it step by step.

  1. How can you get the price of an order line?
BigDecimal getPrice(OrderLine orderLine) {
 return orderLine.getProduct()
 .getPrice()
 .multiply(BigDecimal.valueOf(orderLine.getQuantity()));
}
  1. How can you get the total price of an order?
BigDecimal getPrice(Order order) {
 return order.getOrderLines()
 .stream()
 .map(orderLine -> getPrice(orderLine))
 .collect(reducing(BigDecimal.ZERO, BigDecimal::add));
}
  1. Now assuming you have implemented the methods above, how can you determine the total money spent per each customer?
Map<Customer, BigDecimal> totalPerCustomer =
 orders.stream()
 .collect(groupingBy(Order::getCustomer,
 reducing(BigDecimal.ZERO, o -> getPrice(o), BigDecimal::add)));
  1. Now as you have all the information stored in a convenient map, how can you determine which customer spent the most money?
Optional<Customer> topCustomer = 
 totalPerCustomer.entrySet()
 .stream()
 .max(Map.Entry.comparingByValue())
 .map(Map.Entry::getKey);

Note that topCustomer will be equal to Optional.empty() if the list of orders is empty.

answered Mar 9, 2021 at 12:25
1
  • That's perfect, thanks for the explanation, i got it :D Commented Mar 9, 2021 at 20:21

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.