Filtered Stream with any match on two objects set a value of one object to the value of another object

Viewed 86

Long time reader/ lurker in the shadows, first time poster. Might be a bit of a silly question and I am sure there is an easy solution.

What I have is a List of Customers and a List of Suppliers

Customers:

    private int ID;
    private String name;
    private Integer age;
    private LocalDateTime createdDate;
    private String supplerName;

Suppliers

    private int ID;
    private String name;
    private Integer age;
    private int customerID;
    private LocalDateTime createdDate;

I am fetching some dummy info with:

List<Supplier> suppliersList = supplierRepository.findAll();
List<Customer> customersList = customerRepository.findAll();

Which is returning me something like this:

Suppliers List:
==============================================================================================
  Supplier{ID=1, name='Supplier A', age=19, customerID=1, createdDate=2020-09-25T23:15:31.798}
, Supplier{ID=2, name='Supplier B', age=20, customerID=1, createdDate=2020-09-25T23:15:31.799}
, Supplier{ID=3, name='Supplier C', age=21, customerID=2, createdDate=2020-09-25T23:15:31.799}
, Supplier{ID=4, name='Supplier D', age=22, customerID=3, createdDate=2020-09-25T23:15:31.799}
==============================================================================================
Customers List:
  Customer{ID=1, name='Customer A', age=19, createdDate=2020-09-25T23:15:31.770}
, Customer{ID=2, name='Customer B', age=20, createdDate=2020-09-25T23:15:31.779}
, Customer{ID=3, name='Customer C', age=21, createdDate=2020-09-25T23:15:31.779}
, Customer{ID=4, name='Customer D', age=22, createdDate=2020-09-25T23:15:31.779}
==============================================================================================

Basically what I want to do is if the customerID in Suppliers matches the ID in customer I want to set the supplierName in customers to the name value from Suppliers.

I already have a stream that is finding me the matches

List<Customer> filteredList = customersList.stream()
                .filter(cust -> suppliersList.stream()
                        .anyMatch(supl -> String.valueOf(cust.getID())
                                .equals(String.valueOf(supl.getCustomerID())))
                ).collect(Collectors.toList());

which gives me the following output for the 3 matched ID's

  Customer{ID=1, name='Customer A', age=19, createdDate=2020-09-25T23:22:16.768}
, Customer{ID=2, name='Customer B', age=20, createdDate=2020-09-25T23:22:16.776}
, Customer{ID=3, name='Customer C', age=21, createdDate=2020-09-25T23:22:16.777}

So long story short what I am trying to achieve is for all these matches I want to set the Customer supplierName to the name value in Supplier.

At some point I would also like to also join another stream of objects (so we would now have 3 streams) and set one or multiple values from one object to another. Bonus points if anyone has a solution for that :)

1 Answers

I think this task is better done without a pure stream solution. Here it is, separated in steps:

Map<Integer, List<Supplier>> suppliersByCustomerId = suppliersList.stream()
        .collect(Collectors.groupingBy(Supplier::getCustomerID));

This groups suppliers by customerID. Then, we need to iterate the customers and check if there are suppliers for each one of them. If there's a match, we set the name of the first supplier to the customer.

customers.forEach(c -> {
    List<Supplier> suppliers = suppliersByCustomerId.get(c.getID());
    if (suppliers != null && !suppliers.isEmpty()) {
        Supplier first = suppliers.get(0);
        String suppliername = first.getName();
        c.setSupplierName(supplierName);
    }
});

As you are not specifying what to do if there are many suppliers per customer, I've decided to set the name of the first supplier to the customer.

Related