Java - 列表中每个重复订单的汇总订单数量
Java - Rollup Order quanity for each duplicate order in a list
使用下面提供的代码,我想要实现的是:
我有订单进来,如果列表中有相同产品的订单 - 按产品名称标识,我必须增加第一个订单的数量并删除其他类似订单。
下表中类似订单的示例:P3 和 P4。
但是这种方法会导致异常,想知道你们是否可以建议任何其他方法。
这是一个示例列表,我的列表通常包含 800 个或更多订单。
public class RollUpLogic {
public static void main(String[] args) {
List<Order> orderList = new ArrayList<Order>();
orderList.add(new Order("P1", 1));
orderList.add(new Order("P2", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P4", 1));
orderList.add(new Order("P4", 2));
//if same product ordered, Rollup the quantity and remove duplicate orders
Iterator<Order> iterator = orderList.iterator();
while(iterator.hasNext()) {
Order order = iterator.next();
int firstIndex = orderList.indexOf(order);
int lastIndex = orderList.lastIndexOf(order);
while(firstIndex!=lastIndex) {
//+1 qty of firstindex order
order.setProductQTY(order.getProductQTY()+1);
//remove order at lastIndex
orderList.remove(lastIndex); //throws concurrent modification exception
lastIndex = orderList.lastIndexOf(order);
}
}
}
}
class Order{
private String productName;
private int productQTY;
public Order(String productName, int productQTY) {
super();
this.productName = productName;
this.productQTY = productQTY;
}
public int getProductQTY() {
return productQTY;
}
public void setProductQTY(int productQTY) {
this.productQTY = productQTY;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((productName == null) ? 0 : productName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Order other = (Order) obj;
if (productName == null && other.productName != null) {
return false;
} else if (!productName.equals(other.productName))
return false;
return true;
}
}
我建议您创建另一个包含分组订单的列表。
这对内存来说不是什么大问题,因为您将添加引用。
您可以简单地创建一个新列表,而不用修改现有列表。迭代集合时不能使用 Collection.remove
(或 add
等),这就是导致异常的原因。
为了提高效率,您可以使用 LinkedHashMap
。
LinkedHashMap<Order> orderMap = new LinkedHashMap<Order>();
for (Order order: orderList) {
String orderName = order.getProductName();
if (orderMap.containsKey(orderName)) {
Order existing = orderMap.get(orderName);
existing.setProductQty(existing.getProductQty() + order.getProductQty());
} else {
orderMap.put(orderName, order);
}
}
// optionally, copy back to the list
orderList.clear();
for (Order order: orderMap.values()) {
orderList.add(order);
}
您尝试实现的基本上是一个从 String (productName) 到 int (quantity) 的 MultiMap。为什么不使用一个(例如 guava has a nice general implementation, or you could use a trove TObjectIntHashMap 及其 adjustOrPutValue
方法)?
您还可以在 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html
中使用一些并发实现
使用 Map<String, Integer>
,您可以在其中跟踪每个产品名称的商品数量:
Map<String, Integer> productQuantity = new HashMap<>();
for(Order o : orderList) {
Integer q = productQuantity.get(o.getProductName());
int newQ = o.getProductQTY() + (q == null ? 0 : q.intValue());
productQuantity.put(o.getProductName(), newQ);
}
然后您可以将此地图转换为更新订单的“列表”。
使用下面提供的代码,我想要实现的是: 我有订单进来,如果列表中有相同产品的订单 - 按产品名称标识,我必须增加第一个订单的数量并删除其他类似订单。
下表中类似订单的示例:P3 和 P4。
但是这种方法会导致异常,想知道你们是否可以建议任何其他方法。
这是一个示例列表,我的列表通常包含 800 个或更多订单。
public class RollUpLogic {
public static void main(String[] args) {
List<Order> orderList = new ArrayList<Order>();
orderList.add(new Order("P1", 1));
orderList.add(new Order("P2", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P3", 1));
orderList.add(new Order("P4", 1));
orderList.add(new Order("P4", 2));
//if same product ordered, Rollup the quantity and remove duplicate orders
Iterator<Order> iterator = orderList.iterator();
while(iterator.hasNext()) {
Order order = iterator.next();
int firstIndex = orderList.indexOf(order);
int lastIndex = orderList.lastIndexOf(order);
while(firstIndex!=lastIndex) {
//+1 qty of firstindex order
order.setProductQTY(order.getProductQTY()+1);
//remove order at lastIndex
orderList.remove(lastIndex); //throws concurrent modification exception
lastIndex = orderList.lastIndexOf(order);
}
}
}
}
class Order{
private String productName;
private int productQTY;
public Order(String productName, int productQTY) {
super();
this.productName = productName;
this.productQTY = productQTY;
}
public int getProductQTY() {
return productQTY;
}
public void setProductQTY(int productQTY) {
this.productQTY = productQTY;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((productName == null) ? 0 : productName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Order other = (Order) obj;
if (productName == null && other.productName != null) {
return false;
} else if (!productName.equals(other.productName))
return false;
return true;
}
}
我建议您创建另一个包含分组订单的列表。 这对内存来说不是什么大问题,因为您将添加引用。
您可以简单地创建一个新列表,而不用修改现有列表。迭代集合时不能使用 Collection.remove
(或 add
等),这就是导致异常的原因。
为了提高效率,您可以使用 LinkedHashMap
。
LinkedHashMap<Order> orderMap = new LinkedHashMap<Order>();
for (Order order: orderList) {
String orderName = order.getProductName();
if (orderMap.containsKey(orderName)) {
Order existing = orderMap.get(orderName);
existing.setProductQty(existing.getProductQty() + order.getProductQty());
} else {
orderMap.put(orderName, order);
}
}
// optionally, copy back to the list
orderList.clear();
for (Order order: orderMap.values()) {
orderList.add(order);
}
您尝试实现的基本上是一个从 String (productName) 到 int (quantity) 的 MultiMap。为什么不使用一个(例如 guava has a nice general implementation, or you could use a trove TObjectIntHashMap 及其 adjustOrPutValue
方法)?
您还可以在 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html
中使用一些并发实现使用 Map<String, Integer>
,您可以在其中跟踪每个产品名称的商品数量:
Map<String, Integer> productQuantity = new HashMap<>();
for(Order o : orderList) {
Integer q = productQuantity.get(o.getProductName());
int newQ = o.getProductQTY() + (q == null ? 0 : q.intValue());
productQuantity.put(o.getProductName(), newQ);
}
然后您可以将此地图转换为更新订单的“列表”。