Java рассчитывает максимальную цену клиента, используя потоки - PullRequest
0 голосов
/ 08 октября 2018

У меня проблема с потоками.У меня много Customer объектов, и я хотел бы рассчитать, какой из них заплатил больше всего.

Это мои примерные данные:

class Orders {

    private List<Order> orders = new ArrayList<>();

    public void prepareData() {

        Product socks = new ProductBuilder()
                .setPrice(new BigDecimal("23"))
                .setCategory(Category.C)
                .setName("SOCKS")
                .build();

        Product jacket = new ProductBuilder()
                .setPrice(new BigDecimal("199"))
                .setCategory(Category.A)
                .setName("JACKET")
                .build();

        Product watch = new ProductBuilder()
                .setPrice(new BigDecimal("100"))
                .setCategory(Category.B)
                .setName("WATCH CASIO")
                .build();


        Customer john = new CustomerBuilder()
                .setAge(18)
                .setName("JOHN")
                .setSurname("JOHNSON")
                .setEmail("john@johnson.com")
                .build();

        Customer mike = new CustomerBuilder()
                .setAge(20)
                .setName("MIKE")
                .setSurname("MAX")
                .setEmail("mike@max.com")
                .build();


        Order orderJohn = new OrderBuilder()
                .setQuantity(2)
                .setCustomer(john)
                .setProduct(watch)
                .setOrderDate(LocalDate.now())
                .build();

        Order orderJohn2 = new OrderBuilder()
                .setQuantity(4)
                .setCustomer(john)
                .setProduct(socks)
                .setOrderDate(LocalDate.now())
                .build();


         Order orderMike = new OrderBuilder()
                .setQuantity(2)
                .setCustomer(mike)
                .setProduct(jacket)
                .setOrderDate(LocalDate.now())
                .build();

        orders.add(orderJohn);
        orders.add(orderJohn2);
        orders.add(orderMike);
    }
}

Теперь я должен сгруппировать по клиенту, потому что одинУ клиента много заказов, и вы рассчитываете цену * и количество и выбираете максимум, используя orders.stream()?Как я могу это сделать?

Мои определения классов:

public class Order {

    private Customer customer;
    private Product product;
    private int quantity;
    private LocalDate orderDate;
   //get/set
}
public class Customer {

    private String name;
    private String surname;
    private int age;
    private String email;
    //get/set
}
public class Product {
    private String name;
    private BigDecimal price;
    private Category category;
    //get/set
}

И строители

    public class CustomerBuilder {

        private Customer customer = new Customer();

        public CustomerBuilder setName(String name){
            customer.setName(name);
            return this;
        }

        public CustomerBuilder setSurname(String surname){
            customer.setSurname(surname);
            return this;
        }

        public CustomerBuilder setAge(int age){
            customer.setAge(age);
            return this;
        }

        public CustomerBuilder setEmail(String email){
            customer.setEmail(email);
            return this;
        }

        public Customer build()  {

            return customer;
        }

    }
public class OrderBuilder {
   private Order order = new Order();

   public OrderBuilder setCustomer(Customer customer){
       order.setCustomer(customer);
       return this;
   }

   public OrderBuilder setProduct(Product product){
       order.setProduct(product);
       return this;
   }

   public OrderBuilder setQuantity(int quantity){
       order.setQuantity(quantity);
       return this;
   }

   public OrderBuilder setOrderDate(LocalDate orderDate){
       order.setOrderDate(orderDate);
       return this;
   }

   public Order build(){
       return order;
   }

}
public class ProductBuilder {

    private Product product = new Product();

    public ProductBuilder setCategory(Category category){
        product.setCategory(category);
        return this;
    }

    public ProductBuilder setName(String name){
        product.setName(name);
        return this;
    }

    public ProductBuilder setPrice(BigDecimal bigDecimal){
        product.setPrice(bigDecimal);
        return this;
    }

    public Product build() {
        return product;
    }
}

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Следующее находит главного клиента, сначала группируя его по полю customer (сопоставленному с общей суммой соответствующей стоимости покупки [quantity * price]).

Затем результат этой агрегации просматривается, чтобы найти"max" от общей стоимости покупки.

Customer topCustomer = orders.stream()
        .collect(Collectors.groupingBy(Order::getCustomer,
                Collectors.mapping(
                        order -> order.getProduct()
                                      .getPrice()
                                      .multiply(new BigDecimal(order.getQuantity())),
                        Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
        .entrySet().stream()
        .max(Comparator.comparing(Entry::getValue))
        .map(Entry::getKey)
        .orElse(null);

Важно отметить, что это предполагает, что hashCode() и equals() правильно переопределены в Customer для правильной работы группировки.

РЕДАКТИРОВАТЬ:

Если также требуется общая сумма покупок, вам нужно будет получить полную запись вместо сопоставления только с ключом (приведенный ниже код основан на фрагменте выше):

Optional<Entry<Customer, BigDecimal>> topCustomerEntry = orders.stream()
        .collect(Collectors.groupingBy(Order::getCustomer,
                Collectors.mapping(order -> 
                    order.getProduct()
                            .getPrice()
                            .multiply(new BigDecimal(order.getQuantity())),
                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
        .entrySet().stream()
        .max(Comparator.comparing(Entry::getValue));

BigDecimal topValue = null; //total value for top customer
Customer customer = null;   //customer with most purchases

if(topCustomerEntry.isPresent()) {
    topValue = topCustomerEntry.get().getValue();
    customer = topCustomerEntry.get().getKey();
}

Это просто напечатает значения.Но вы можете реструктурировать код, чтобы присвоить их переменной.

0 голосов
/ 08 октября 2018

Если вам нужен клиент, который тратит больше всего (например, по электронной почте):

  orders.stream()
            .collect(Collectors.toMap(
                    x -> x.getCustomer().getEmail(),
                    x -> x.getProduct().getPrice().multiply(new BigDecimal(x.getQuantity())),
                    BigDecimal::add))
            .entrySet()
            .stream()
            .max(Entry.comparingByValue())
            .ifPresent(System.out::println);
...