Aravi S
Aravi S

Reputation: 109

How to remove duplicate entries form ArrayList in java

I want to remove duplicate entry based on productId and priceTagId. If we remove the duplicates we need to add the quantity

here in productDetails list same productId is there but quantity is different if i need to add the quantity into one

"productDetails" : [
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 2,
            "netQty" : "10mg",
            "priceTagId" : 1,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 4,
            "netQty" : "10mg",
            "priceTagId" : 1,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 6,
            "netQty" : "30mg",
            "priceTagId" : 3,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 8,
            "netQty" : "30mg",
            "priceTagId" : 3,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "2345dfb7d991390e25edf659",
            "quantity" : 8,
            "netQty" : "30mg",
            "priceTagId" : 3,
            "alertAvailablity" : "Success"
        }
    ],

I got final output as

"productDetails" : [
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 6,
            "netQty" : "10mg",
            "priceTagId" : 1,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "5764dfb7d991390e25edff74",
            "quantity" : 14,
            "netQty" : "30mg",
            "priceTagId" : 3,
            "alertAvailablity" : "Success"
        },
        {
            "productId" : "2345dfb7d991390e25edf659",
            "quantity" : 8,
            "netQty" : "30mg",
            "priceTagId" : 3,
            "alertAvailablity" : "Success"
        }

    ],

Based on the productId and priceTagId i need to remove duplicates and add quantity from the removed duplicates entry

private List<ProductDetail> removeDuplicateProducts(List<ProductDetail> productDetails) throws BaseException {
    for (ProductDetail eachProductDetail : productDetails) {
        for (ProductDetail eachInnerProductDetail : productDetails) {
            if(eachProductDetail.getProductId().equals(eachInnerProductDetail.getProductId()))
            {
                if(eachProductDetail.getPriceTagId().equals(eachInnerProductDetail.getPriceTagId()))
                {
                    eachProductDetail.setQuantity(eachProductDetail.getQuantity()+eachInnerProductDetail.getQuantity());
                    productDetails.clear();
                }
            }

        }
    }           
    return productDetails;
}

But i dint get it wy? What wrong?

Upvotes: 5

Views: 197

Answers (6)

Selvakumar Ponnusamy
Selvakumar Ponnusamy

Reputation: 5533

You can use set to remove duplicates and change the quantity in equals method of ProductDetail class

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class Test {
public static void main(String[] args) {
    List<ProductDetail> productDetails = new ArrayList<ProductDetail>();
    ProductDetail p1 = new ProductDetail("1", "pt1", 10);
    ProductDetail p2 = new ProductDetail("1", "pt1", 40);
    ProductDetail p3 = new ProductDetail("2", "pt1", 30);

    productDetails.add(p1);
    productDetails.add(p2);
    productDetails.add(p3);

    List<ProductDetail> list = removeDuplicateProducts(productDetails);
    for (ProductDetail p : list) {
        System.out.println(p);
    }

}

private static List<ProductDetail> removeDuplicateProducts(
        List<ProductDetail> productDetails) {

    Set<ProductDetail> set = new LinkedHashSet<ProductDetail>(
            productDetails);

    List<ProductDetail> list = new ArrayList<ProductDetail>();
    list.addAll(set);

    return list;
}

private static class ProductDetail {
    public ProductDetail(String productId, String priceTagId, int quantity) {
        this.productId = productId;
        this.priceTagId = priceTagId;
        this.quantity = quantity;
    }

    String productId;
    String priceTagId;
    int quantity;

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getPriceTagId() {
        return priceTagId;
    }

    public void setPriceTagId(String priceTagId) {
        this.priceTagId = priceTagId;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return (this.productId+"--"+this.priceTagId+"--"+this.quantity);

    }

    @Override
    public int hashCode() {
        return (this.priceTagId.hashCode()*this.priceTagId.hashCode());
    }

    @Override
    public boolean equals(Object obj) {
        ProductDetail p1 = (ProductDetail) obj;
        if ((p1.getPriceTagId().equals(this.getPriceTagId()) && p1
                .getProductId().equals(this.getProductId()))) {
            p1.setQuantity(this.getQuantity() + p1.getQuantity());
            return true;
        }
        return false;
    }
}

}

Upvotes: 0

Victor Bayona
Victor Bayona

Reputation: 21

You could change the approach to return a new list with the data that you need.

private List<ProductDetail> removeDuplicateProducts(List<ProductDetail> productDetails) {

    List<ProductDetail> returnList = new ArrayList<ProductDetail>();
    boolean exists = false;

    for (ProductDetail eachProductDetail : productDetails) {
        exists = false;
        for (ProductDetail eachInnerProductDetail : returnList) {
            // Your match condition
            if (eachProductDetail.getProductId().equals(eachInnerProductDetail.getProductId())
              && eachProductDetail.getPriceTagId().equals(eachInnerProductDetail.getPriceTagId()) ) {
                exists = true;
                eachInnerProductDetail.setQuantity(eachProductDetail.getQuantity() + eachInnerProductDetail.getQuantity());
                break; 
            }
        }

        // add to output list if not exists
        if (!exists){
            returnList.add(eachProductDetail);
        }

    }
    return returnList;
}

By this way you can have the original list and the new one.

Upvotes: 0

vhreal
vhreal

Reputation: 1

In your code, if you use "for each" statement like that, an element of the list always has one time that it is compared with itself and this will give the wrong result. You should use index to access elements of the list

for (int i = 0; i <= list.size() - 1; i++) {
 for (int j = i + 1; j <= list.size() - 1; j++) {
  <enter your if statements here>
 }
}

and rememeber to remove the duplicate element by using list.remove(indexOfTheDuplicate), list.clear() will remove all elements of the list.

Upvotes: 0

Facepalmed
Facepalmed

Reputation: 761

In this example I would use a map. Let's see why:

private List<ProductDetail> removeDuplicateProducts(List<ProductDetail> productDetails) throws BaseException {

Same method signature would be ok. Now, the difference

//This map will contain the final set of elements
Map<Integer, ProductDetail> map = new HashMap<Integer, ProductDetail>();

for (ProductDetail item: productDetails){
    //If map already contains the same productId it adds the quantities but doesn't add the same productId again
    if(map.containsKey(item.getProductId())){
        ProductDetail mapItem = map.get(item.getProductId());
        mapItem.setQuantity(mapItem.getQuantity() + item.getQuantity());
    }
    //If map doesn't contain the same productId, it's added for the first time
    else{
        mapItem.put(item.getProductId(), item);
    }
}

//At this point the map only contains a set of different productId. Now it will be dumped into a list and returned.
return new ArrayList<String>(map.values());

I hope it helps

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533442

The most efficient solution is to use a Map where the key is a combination of all the fields you consider to make the products the same and the value contains any additional information.

In your case you could do

private Collection<ProductDetail> accumulateDuplicateProducts(List<ProductDetail> productDetails) {
    // use a map to quickly find entries which match.
    // using a linked HashMap means the order of addition is preserved.
    Map<String, ProductDetail> productMap = new LinkedHashMap<>();
    for (ProductDetail pd : productDetails) {
        // build a composite key of the fields you want to match on.
        String key = pd.getProductId() + " " + pd.getPriceTag();
        // if the Strings match they should be merged.
        // if there was no previous entry, use the current one.
        // if there was a previous entry call merge() to combine them.
        productMap.compute(key, (k, pd2) -> pd2 == null ? pd : merge(pd, pd2));
    }
    return productMap.values();
}

private static ProductDetail merge(ProductDetail pd, ProductDetail pd2) {
    // combine two ProductDetails
}

Note: the time complexity is O(n) instead of O(n^2) if you use two nested loops.

But i dint get it wy? What wrong?

One problem you have is

productDetails.clear();

another problem you have is that you compare every entry against every entry e.g. say you have two entries A and B which match

A is compared with A so A *= 2
A is compared with B do A += B
B is compared with A so B += A
B is compared with B so B *= 2

You still end up with two entries, as you are not removing one.

Upvotes: 3

assylias
assylias

Reputation: 328568

I would create a ProductKey class:

class ProductKey {
  private final Integer productId;
  private final Integer priceTagId;
  //constructor, getters, equals, hashcode
}

Then put all the products in a Map<ProductKey, List<ProductDetail>> where the key is an instance of the class above and the value is the list of all products that match the ProductKey.

Then merge the elements of each list by summing the quantities etc.

You can also probably run those two steps in one go.

Upvotes: 1

Related Questions