How to do for inside for with some condition with java 8 Streams

I have the following code:

List<SoldProduct> soldProducts = new ArrayList<>();
    for (Product product : products) {
        for (ProductCartDTO productCartDTO : dto.getProducts()) {
            if(product.getId().equals(productCartDTO.getIdProduct())){
               soldProducts.add(new SoldProduct(product, productCartDTO.getSerialList()));
            }
        }
    }

I tried many times but can't get the same result with Java 8 Streams.

Is it possible to get this exact behaviour with Streams? If yes, please, give me an example.

Thanks

Upvotes: 1

Views: 196

Answers (2)

shmosel
shmosel

Reputation: 50716

As @Andreas said, your nested loop approach is not very efficient, but here's how you can convert it to streams:

List<SoldProduct> soldProducts = products.stream()
    .flatMap(product -> dto.getProducts()
        .stream()
        .filter(productCartDTO -> product.getId().equals(productCartDTO.getIdProduct()))
        .map(ProductCartDTO::getSerialList)
        .map(serialList -> new SoldProduct(product, serialList)))
    .collect(Collectors.toList());

Upvotes: 1

Andreas
Andreas

Reputation: 159086

A cartesian join of two lists, to find objects with matching product id, is very bad for performance.

Suggest you build a Map<Integer, Product>, of course assuming there can be only one product with a given id.

Map<Integer, Product> productById =
        products.stream()
                .collect(Collectors.toMap(Product::getId, Function.identity()));

List<SoldProduct> soldProducts =
        dto.getProducts()
           .stream()
           .filter(d -> productById.containsKey(d.getIdProduct()))
           .map(d -> new SoldProduct(productById.get(d.getIdProduct()), d.getSerialList()))
           .collect(Collectors.toList());

The code is not any prettier than the original code, and now that it has been optimized to use a Map for faster product lookup, you likely won't need parallel processing, so you might as well stick with the original code.

Or rather, fix the original code to use Map too:

Map<Integer, Product> productById = new HashMap<>();
for (Product product : products)
    productById.put(product.getId(), product);

List<SoldProduct> soldProducts = new ArrayList<>();
for (ProductCartDTO productCartDTO : dto.getProducts()) {
    Product product = productById.get(productCartDTO.getIdProduct());
    if (product != null) {
        soldProducts.add(new SoldProduct(product, productCartDTO.getSerialList()));
    }
}

Upvotes: 3

Related Questions