Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArrayList 'squash' operation on its elements

I have a problem that seems to be trivial but I'm looking for the best way of resolving that issue.

Let's say I have a class:

Product.class

public class Product {
    private int id;
    private String code;
    private String price;
    private String quantity;

    public Product() {}

    //getters and setters

    @Override
    public boolean equals(Object obj) {
        boolean result = false;
        if (obj instanceof ProductOnStockDto) {
            ProductOnStockDto product = (ProductOnStockDto) obj;
            result = (this.code.equals(product.getCode()) && this.price.equals(product.getPrice()));
        }
        return result;
    }
}

And let's say I have a list of this objects:

List<Product> products;

Which is filled with data like this(1 row is one list element):

And what I need is to iterate over this list and squash elements that have the same code and the same price. For example:

In the result list I would like to have two products for code 3:

code 3 | 1.22 | 11
code 3 | 2.20 | 6

So I would do sth like this:

for(Product product : products) {
    for(Product productToSquash : products) {
        if(product.getId() != productToSquash.getId() && product.equals(productToSquash)) {
            //Here I would like to squash these two rows
            //Data conversion is ommited
            product.setQuantity(product.getQuantity() + productToSquash.getQuantity());
            //after that I would like to remove productToSquash object from the collection
        }
    }
}

But as I know it is not allowed to modify collection that I'm iterating on. So what would be the best way to squash all product list according to the example?

like image 424
Daniel Urbaniak Avatar asked May 14 '26 15:05

Daniel Urbaniak


1 Answers

First of all, your equals() method refers to ProductOnStockDto. That should be Product.

To remove elements during iteration, use the Iterator directly, i.e. use an "old style" for-loop, and use a Map<Product, Product> to keep track of products previously seen. This requires that you also implement hashCode():

@Override
public int hashCode()
{
    return this.code.hashCode() * 37 + this.price.hashCode();
}
Map<Product, Product> map = new HashMap<Product, Product>();
for (Iterator<Product> productIter = products.iterator(); productIter.hasNext(); ) {
    Product product = productIter.next();
    Product productToKeep = map.get(product);
    if (productToKeep == null)
        map.put(product, product);
    else {
        productToKeep.setQuantity(productToKeep.getQuantity() + product.getQuantity());
        productIter.remove();
    }
}

You shouldn't really be doing it this way, since the equals() method is returning true for objects that are not truly equal.

You should instead have a key class with just code and price, and the key class is one that needs to implement equals() and hashCode(), not Product.

like image 66
Andreas Avatar answered May 16 '26 04:05

Andreas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!