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 ?
CodePudding user response:
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());
CodePudding user response:
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);