1

I have a list of product exampe

List<Product> productList = [product1, product2,product2, product3, product3, product5];

My product class is

public class Product {
 private long productId;
 private String productName;
 private double productPrice;
 ... getters and setters
}

I want to have two list : the first returns only product which occur more than once and the second returns product which occur only once

I am using Streams with java 8

List<Product> productMoreThanOnce = new ArrayList<>();
List<Product> productOnlyOnce = new ArrayList<>();
productMoreThanOnce = productList.stream().filter(e-> Collections.frequency(productList, e) > 1).distinct().collect(Collectors.toList());

productOnlyOnce  = productList.stream().filter(e-> Collections.frequency(productList, e) == 1).distinct().collect(Collectors.toList());

but productMoreThanOnce doesn't returns duplicated product => [product2,product3]

what is the best way to do this ?

3
  • Are you sure you are using the same objects for duplicate products? What I mean is: when you say two products are identical, do you mean they point to the same object, or to two objects with identical fields? If it is the latter case, you need to provide a custom equals method to facilitate comparison. Commented Feb 25, 2022 at 15:04
  • Hi @GhareebFalazi, it is the latter case. Two products objects are equals if they are identicals fields. How can i give the equals methode with Stream java to have two list Commented Feb 25, 2022 at 15:08
  • 3
    Always edit your question. Dont provide more information in comments. Ensure the question is self contained! Commented Feb 25, 2022 at 15:18

2 Answers 2

2

You can group within the stream:

Map<Product, Long> map = productList.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

here each key has associated number of occurrences as value.

Then you can retrieve unique elements:

List<Product> unique = map.entrySet().stream()
    .filter(e -> e.getValue() == 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

And retrieve duplicate elements:

List<Product> duplicate = map.entrySet().stream()
    .filter(e -> e.getValue() > 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

2 Comments

Hi @Andronicus , when in List<Product> unique = collect.entrySet().stream() .filter(e -> e.getValue() == 1) .map(Map.Entry::getKey) .collect(Collectors.toList()); my code doesn 't compile because of collect, It says me create a local variable collect
@ln3106 yes, it should be map, I've corrected it
1

Add and override equals and hashcode methods in your Product class, if you have not already done so. Example:

@Override
public boolean equals(final Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof Product)) {
        return false;
    }
    final Product product = (Product) o;
    return productId == product.productId && Double.compare(product.productPrice, productPrice) == 0
            && Objects.equals(productName, product.productName);
}

@Override
public int hashCode() {
    return Objects.hash(productId, productName, productPrice);
}

You can then use a partitioning collector from the streams api:

Map<Boolean,List<Product>> map = productList.stream()
        .collect(Collectors.partitioningBy(e -> Collections.frequency(productList, e) > 1));

List<Product> productMoreThanOnce = map.get(true);
List<Product> productOnlyOnce     = map.get(false);

Comments

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.