如何在对相似元素求和后获得列表
How to obtain a list after sum over similar elements
我有一个产品列表 class,它具有以下属性:
public class Products{
private int month;
private int year;
private int sku;
private String detail;
private Double quantity;
private Double price;
private Double discount;
private Double %discount;
// getters and setters
static List<Products> sumProduct(List<Products> itemList) {
List<Product> tempListP = new ArrayList<Product>();
Collections.sort(itemList, Comparator.comparing(Product::getYear)
.thenComparing(Product::getMonth).thenComparing(Product::getSku));
Integer itemCode = null;
double quantiti = 0;
double price = 0;
double discount = 0;
double %discount = 0;
Products itemObj = null;
Integer itemMonth= null;
Integer itemYear= null;
for (int i = 0; i < itemList.size(); i++) {
if (itemCode == null || (itemCode.equals(itemList.get(i).getSku()) && itemMonth.equals(itemList.get(i).getMonth()) && itemMonth.equals(itemList.get(i).getYear()) )) {
quantiti = quantiti + itemList.get(i).getquantiti();
price = price + itemList.get(i).getprice();
discount = discount + itemList.get(i).getdiscount();
%discount = %discount + itemList.get(i).get%discount();
itemMonth = itemList.get(i).getMonth();
itemYea = itemList.get(i).getYear();
} else {
itemObj = new Product( itemList.get(i).getMonth(), itemList.get(i).getYear(), itemCode, "" , quantiti, price,discount,%discount);
if (tempListP.contains(itemObj)) {
tempListP.remove(itemObj);
}
tempListP.add(itemObj);
quantiti = 0;
quantiti = quantiti + itemList.get(i).getquantiti();
price = 0;
price = price + itemList.get(i).getprice();
discount = 0;
discount = discount + itemList.get(i).getdiscount();
%discount = 0;
%discount = %discount + itemList.get(i).get%discount();
itemMonth = itemList.get(i).getMonth();
itemYea = itemList.get(i).getYear();
}
itemCode = itemList.get(i).getSku();
if (i == itemList.size() - 1) {
itemObj = new Product( itemList.get(i).getMonth(), itemList.get(i).getYear(), itemCode, "" , quantiti, price,discount,%discount);
tempListP.add(itemObj);
}
}
return itemList;
}
}
主要
public static void main(String[] args) {
List<Products> items = new ArrayList<Products>();
items.add(new Products(8,2020,10203040,"Tshirt",1,10.00,1.00,0.1));
items.add(new Products(9,2020,10203040,"Tshirt",2,20.00,2.00,0.2));
items.add(new Products(3,2021,10203040,"Tshirt",3,30.00,3.00,0.3));
items.add(new Products(7,2020,50607080,"Tshirt",4,40.00,4.00,0.4));
items.add(new Products(8,2020,10203040,"Tshirt",5,50.00,5.00,0.5));
items.add(new Products(8,2021,10203040,"Tshirt",8,80.00,8.00,0.8));
Products.sumProduct(items);
输入
Month | Year | Sku | Detail | Quantity | Price | Discount | % Discount
8 | 2020 | 10203040 | Tshirt | 1 | 10 | 1 | 0.1
9 | 2020 | 10203040 | Tshirt | 2 | 20 | 2 | 0.2
3 | 2021 | 10203040 | Tshirt | 3 | 30 | 3 | 0.3
7 | 2020 | 50607080 | Tshirt | 4 | 40 | 4 | 0.4
8 | 2020 | 10203040 | Tshirt | 5 | 50 | 5 | 0.5
8 | 2021 | 10203040 | Tshirt | 8 | 80 | 8 | 0.8
最终结果应该是这样的:
输出:
Month | Year | Sku | Detail | Quantity | Price | Discount | % Discount
7 | 2020 | 50607080 | Tshirt | 4 | 40 | 4 | 0.4
8 | 2020 | 10203040 | Tshirt | 6 | 60 | 6 | 0.6
9 | 2020 | 10203040 | Tshirt | 2 | 20 | 2 | 0.2
3 | 2021 | 10203040 | Tshirt | 3 | 30 | 3 | 0.3
8 | 2021 | 10203040 | Tshirt | 8 | 80 | 8 | 0.8
我想创建一个函数来遍历产品列表并对具有相同月份、年份和 sku 的项目的价值求和,return 数量、价格总和的列表,折扣,%折扣。
但是我如何将计数和求和链接到上面的代码?特别是对于超过 3 个字段(月、年和 sku)的分组。有更好的方法吗?
我真的需要帮助来对值求和,而不仅仅是对列表中的元素进行分组。
在此先感谢您的帮助。
这个解决方案应该可行,我写了一个比较器来对产品进行排序。然后,如果连续的项目共享相同的值,则对必要的值求和。
比较器
public class ProductsComparator implements Comparator<Products> {
public int compare(Products p1, Products p2) {
int value1 = p1.year.compareTo(p2.year);
if (value1 == 0) {
int value2 = p1.month.compareTo(p2.month);
if (value2 == 0) {
return p1.sku.compareTo(p2.sku);
} else {
return value2;
}
}
return value1;
}
}
求和函数
public static List<Products> sumProducts(List<Products> itemList) {
List<Product> newList = new ArrayList<Product>();
int index = -1;
Collections.sort(itemList, new ProductsComparator());
for(Products item : itemList){
if(newList.size() != 0 && newList.get(index).getYear() == item.getYear() && newList.get(index).getMonth() == item.getMonth() && newList.get(index).getSku() == item.getSku()){
// Add values
newList.get(index).setquantiti(newList.get(index).getquantiti() + item.getquantiti());
newList.get(index).setprice(newList.get(index).getprice() + item.getprice());
newList.get(index).setdiscount(newList.get(index).getdiscount() + item.getdiscount());
newList.get(index).set%discount(newList.get(index).get%discount() + item.get%discount());
}else{
newList.add(item);
index++;
}
}
return newList;
}
如果你想 return 那些统计数据在一个单一的 return 值中,你最好有包含值的结构。这是一个更好的设计,它重新使用乘积 class 来包含聚合。那就是以一种会混淆 reader.
的方式重载 class 的使用
这是记录的一个很好的用例,因为它们为您做了很多工作(例如,为您的整理和聚合定义 equals
和 hashCode
)。您可以添加一些方便的功能来使整理更容易:
record MonthSKU(int month, int year, int sku) {
MonthSKU(Product product) {
this(product.month, product.year, product.sku);
}
}
record ProductStats(double quantity, double price, double discount) {
static ProductStats ZERO = new ProductStats(0, 0, 0);
ProductStats(Product product) {
this(product.quantity, product.price, product.discount);
}
ProductStats combine(ProductStats other) {
return new ProductStats(quantity + other.quantity, price + other.price, discount + other.discount);
}
}
现在使用流运算符进行分组和求和非常简单:
Map<MonthSKU,ProductStats> stats = productList.stream()
.collect(groupingBy(MonthSKU::new,
reducing(ProductStats.ZERO, ProductStats::new, ProductStats::combine));
在我看来,与包含聚合值的产品列表和需要排序列表的算法相比,这是一个更易于理解的输出统计模型 - 这既难以理解又容易破解。
此模型也更容易扩展以添加新字段或更复杂的统计信息(例如维护计数以计算平均值)。所有这些更改都可以通过更改 2 条记录来完成,而根本不更改分组和减少操作。
类似地,'details' 字段似乎包含与 sku 而非产品相关的信息。如果是这样,您应该将它们放在单独的 Map<Integer,String>
或专用的 SKU
class 中。如果不是,那么当产品具有相同的 sku 但不同的细节时,您需要确定在汇总摘要中打印什么。
我有一个产品列表 class,它具有以下属性:
public class Products{
private int month;
private int year;
private int sku;
private String detail;
private Double quantity;
private Double price;
private Double discount;
private Double %discount;
// getters and setters
static List<Products> sumProduct(List<Products> itemList) {
List<Product> tempListP = new ArrayList<Product>();
Collections.sort(itemList, Comparator.comparing(Product::getYear)
.thenComparing(Product::getMonth).thenComparing(Product::getSku));
Integer itemCode = null;
double quantiti = 0;
double price = 0;
double discount = 0;
double %discount = 0;
Products itemObj = null;
Integer itemMonth= null;
Integer itemYear= null;
for (int i = 0; i < itemList.size(); i++) {
if (itemCode == null || (itemCode.equals(itemList.get(i).getSku()) && itemMonth.equals(itemList.get(i).getMonth()) && itemMonth.equals(itemList.get(i).getYear()) )) {
quantiti = quantiti + itemList.get(i).getquantiti();
price = price + itemList.get(i).getprice();
discount = discount + itemList.get(i).getdiscount();
%discount = %discount + itemList.get(i).get%discount();
itemMonth = itemList.get(i).getMonth();
itemYea = itemList.get(i).getYear();
} else {
itemObj = new Product( itemList.get(i).getMonth(), itemList.get(i).getYear(), itemCode, "" , quantiti, price,discount,%discount);
if (tempListP.contains(itemObj)) {
tempListP.remove(itemObj);
}
tempListP.add(itemObj);
quantiti = 0;
quantiti = quantiti + itemList.get(i).getquantiti();
price = 0;
price = price + itemList.get(i).getprice();
discount = 0;
discount = discount + itemList.get(i).getdiscount();
%discount = 0;
%discount = %discount + itemList.get(i).get%discount();
itemMonth = itemList.get(i).getMonth();
itemYea = itemList.get(i).getYear();
}
itemCode = itemList.get(i).getSku();
if (i == itemList.size() - 1) {
itemObj = new Product( itemList.get(i).getMonth(), itemList.get(i).getYear(), itemCode, "" , quantiti, price,discount,%discount);
tempListP.add(itemObj);
}
}
return itemList;
}
}
主要
public static void main(String[] args) {
List<Products> items = new ArrayList<Products>();
items.add(new Products(8,2020,10203040,"Tshirt",1,10.00,1.00,0.1));
items.add(new Products(9,2020,10203040,"Tshirt",2,20.00,2.00,0.2));
items.add(new Products(3,2021,10203040,"Tshirt",3,30.00,3.00,0.3));
items.add(new Products(7,2020,50607080,"Tshirt",4,40.00,4.00,0.4));
items.add(new Products(8,2020,10203040,"Tshirt",5,50.00,5.00,0.5));
items.add(new Products(8,2021,10203040,"Tshirt",8,80.00,8.00,0.8));
Products.sumProduct(items);
输入
Month | Year | Sku | Detail | Quantity | Price | Discount | % Discount
8 | 2020 | 10203040 | Tshirt | 1 | 10 | 1 | 0.1
9 | 2020 | 10203040 | Tshirt | 2 | 20 | 2 | 0.2
3 | 2021 | 10203040 | Tshirt | 3 | 30 | 3 | 0.3
7 | 2020 | 50607080 | Tshirt | 4 | 40 | 4 | 0.4
8 | 2020 | 10203040 | Tshirt | 5 | 50 | 5 | 0.5
8 | 2021 | 10203040 | Tshirt | 8 | 80 | 8 | 0.8
最终结果应该是这样的:
输出:
Month | Year | Sku | Detail | Quantity | Price | Discount | % Discount
7 | 2020 | 50607080 | Tshirt | 4 | 40 | 4 | 0.4
8 | 2020 | 10203040 | Tshirt | 6 | 60 | 6 | 0.6
9 | 2020 | 10203040 | Tshirt | 2 | 20 | 2 | 0.2
3 | 2021 | 10203040 | Tshirt | 3 | 30 | 3 | 0.3
8 | 2021 | 10203040 | Tshirt | 8 | 80 | 8 | 0.8
我想创建一个函数来遍历产品列表并对具有相同月份、年份和 sku 的项目的价值求和,return 数量、价格总和的列表,折扣,%折扣。
但是我如何将计数和求和链接到上面的代码?特别是对于超过 3 个字段(月、年和 sku)的分组。有更好的方法吗?
我真的需要帮助来对值求和,而不仅仅是对列表中的元素进行分组。
在此先感谢您的帮助。
这个解决方案应该可行,我写了一个比较器来对产品进行排序。然后,如果连续的项目共享相同的值,则对必要的值求和。
比较器
public class ProductsComparator implements Comparator<Products> {
public int compare(Products p1, Products p2) {
int value1 = p1.year.compareTo(p2.year);
if (value1 == 0) {
int value2 = p1.month.compareTo(p2.month);
if (value2 == 0) {
return p1.sku.compareTo(p2.sku);
} else {
return value2;
}
}
return value1;
}
}
求和函数
public static List<Products> sumProducts(List<Products> itemList) {
List<Product> newList = new ArrayList<Product>();
int index = -1;
Collections.sort(itemList, new ProductsComparator());
for(Products item : itemList){
if(newList.size() != 0 && newList.get(index).getYear() == item.getYear() && newList.get(index).getMonth() == item.getMonth() && newList.get(index).getSku() == item.getSku()){
// Add values
newList.get(index).setquantiti(newList.get(index).getquantiti() + item.getquantiti());
newList.get(index).setprice(newList.get(index).getprice() + item.getprice());
newList.get(index).setdiscount(newList.get(index).getdiscount() + item.getdiscount());
newList.get(index).set%discount(newList.get(index).get%discount() + item.get%discount());
}else{
newList.add(item);
index++;
}
}
return newList;
}
如果你想 return 那些统计数据在一个单一的 return 值中,你最好有包含值的结构。这是一个更好的设计,它重新使用乘积 class 来包含聚合。那就是以一种会混淆 reader.
的方式重载 class 的使用这是记录的一个很好的用例,因为它们为您做了很多工作(例如,为您的整理和聚合定义 equals
和 hashCode
)。您可以添加一些方便的功能来使整理更容易:
record MonthSKU(int month, int year, int sku) {
MonthSKU(Product product) {
this(product.month, product.year, product.sku);
}
}
record ProductStats(double quantity, double price, double discount) {
static ProductStats ZERO = new ProductStats(0, 0, 0);
ProductStats(Product product) {
this(product.quantity, product.price, product.discount);
}
ProductStats combine(ProductStats other) {
return new ProductStats(quantity + other.quantity, price + other.price, discount + other.discount);
}
}
现在使用流运算符进行分组和求和非常简单:
Map<MonthSKU,ProductStats> stats = productList.stream()
.collect(groupingBy(MonthSKU::new,
reducing(ProductStats.ZERO, ProductStats::new, ProductStats::combine));
在我看来,与包含聚合值的产品列表和需要排序列表的算法相比,这是一个更易于理解的输出统计模型 - 这既难以理解又容易破解。
此模型也更容易扩展以添加新字段或更复杂的统计信息(例如维护计数以计算平均值)。所有这些更改都可以通过更改 2 条记录来完成,而根本不更改分组和减少操作。
类似地,'details' 字段似乎包含与 sku 而非产品相关的信息。如果是这样,您应该将它们放在单独的 Map<Integer,String>
或专用的 SKU
class 中。如果不是,那么当产品具有相同的 sku 但不同的细节时,您需要确定在汇总摘要中打印什么。