Issue
I have list of products. I want to sum all the data with the same id
public class Product {
private int id;
private String name;
private double price;
private int quantity;
.....
}
I added the data into a list
List<Product> products = new ArrayList<>();
products.add(new Product(1, "x", 100, 4));
products.add(new Product(4, "y", 200, 2));
products.add(new Product(4, "y", 50, 5));
products.add(new Product(8, "k", 50, 1));
products.add(new Product(10, "m", 1000, 1));
products.add(new Product(1, "x", 100, 1));
So far, I have tried to
Map<Integer, Double> productsByNameCategoryType = products.stream()
.collect(Collectors.groupingBy(Product::getId,
Collectors.collectingAndThen(
Collectors.summarizingDouble(Product::getPrice),
p -> p.getSum())
));
This is too far from my expectation and still trying on it My expectation of the output is
1, x, 200, 5
4, y, 250, 7
8, k, 50, 1
10, m, 1000, 1
Solution
"... I have list of products. I want to sum all the data with the same id ..."
Create a new List to contain the merged Product values.
Traverse products, and then sub-traverse the remaining entries, from i + 1.
Merge the Product values, and add to the new List, if it doesn't already contain the id.
List<Product> l = new ArrayList<>();
Product p, t;
int i, j, k, n = products.size(), m;
boolean b;
for (i = 0; i < n; i++) {
p = products.get(i);
for (j = i + 1; j < n; j++)
if (p.getId() == (t = products.get(j)).getId()) {
p.setPrice(p.getPrice() + t.getPrice());
p.setQuantity(p.getQuantity() + t.getQuantity());
}
b = false;
for (k = 0, m = l.size(); k < m; k++)
if (l.get(k).getId() == p.getId()) {
b = true;
break;
}
if (!b) l.add(p);
}
To simplify the process, provide a method to merge the values.
class Product {
...
void merge(Product p) {
price += p.getPrice();
quantity += p.getQuantity();
}
...
}
for (j = i + 1; j < n; j++)
if (p.getId() == (t = products.get(j)).getId())
p.merge(t);
Alternately, encapsulate the ArrayList class, and implement a merge method.
class ProductList extends ArrayList<Product> {
@Override
public boolean add(Product product) {
return merge(product);
}
boolean merge(Product p) {
for (Product v : this)
if (p.getId() == v.getId()) {
v.setPrice(p.getPrice() + v.getPrice());
v.setQuantity(p.getQuantity() + v.getQuantity());
return true;
}
return super.add(p);
}
}
ProductList products = new ProductList();
products.add(new Product(1, "x", 100, 4));
products.add(new Product(4, "y", 200, 2));
products.add(new Product(4, "y", 50, 5));
products.add(new Product(8, "k", 50, 1));
products.add(new Product(10, "m", 1000, 1));
products.add(new Product(1, "x", 100, 1));
Output
1, x, 200.0, 5
4, y, 250.0, 7
8, k, 50.0, 1
10, m, 1000.0, 1
If you did want to use a stream, utilize the Collectors#toMap method.
And, populate an ArrayList instance, from the collectingAndThen method; a somewhat un-intuitive step.
List<Product> l
= products.stream()
.collect(
Collectors.collectingAndThen(
Collectors.toMap(
Product::getId,
x -> x,
(a, b) -> {
Product p = new Product();
p.merge(b);
return p;
}),
x -> new ArrayList<>(x.values())));
Answered By - Reilas
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.