2016-07-04 22 views
5

Voglio rimuovere la voce duplicata basata su productId e priceTagId. Se togliamo i duplicati abbiamo bisogno di aggiungere la quantitàCome rimuovere le voci duplicate modulo ArrayList in java

qui nella lista sui prodotti stessa productId c'è, ma la quantità è diversa se ho bisogno di aggiungere la quantità in una sola

"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" 
     } 
    ], 

ho ottenuto output finale come

"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" 
     } 

    ], 

sulla base della productId e priceTagId ho bisogno di rimuovere i duplicati e aggiungere quantità dal duplicati rimosso ingresso

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; 
} 

Ma non ce la faccio? Cosa c'è di sbagliato?

+1

Perché non metterli in un set? –

+0

Utilizzare un Set se non si desidera duplicare –

+0

Meglio andare su un Set per evitare le voci duplicate.! –

risposta

1

vorrei creare una classe ProductKey:

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

Poi mettere tutti i prodotti di un Map<ProductKey, List<ProductDetail>> in cui la chiave è un'istanza della classe superiore e il valore è l'elenco di tutti i prodotti che corrispondono al ProductKey.

quindi unire gli elementi di ciascuna lista sommando le quantità ecc

È possibile anche probabilmente eseguire questi due passi in un colpo solo.

0

È possibile utilizzare insieme per rimuovere i duplicati e modificare la quantità in uguale metodo della classe ProductDetail

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; 
    } 
} 

}

+0

Puoi condividerlo usando foreach? –

+0

Modificata la risposta –

+0

la prima risposta che posso capire ma questa non è corretta –

3

La soluzione più efficace è quella di utilizzare una mappa dove la chiave è una combinazione di tutti i campi che consideri per rendere i prodotti uguali e il valore contiene informazioni aggiuntive.

Nel tuo caso si potrebbe fare

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 
} 

Nota: la complessità temporale è O(n) invece di O(n^2) se si utilizzano due cicli annidati.

Ma ho capito? Cosa c'è di sbagliato?

Un problema che hai è

productDetails.clear(); 

un altro problema che hai è che si confrontano per esempio ogni ingresso contro ogni entry dire di avere due voci A e B che corrispondono alla

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 

ancora finire con due voci, in quanto non sta rimuovendo uno.

+0

Non riesco a capirlo Puoi elaborare il tuo codice se hai tempo –

+0

In realtà il mio motivo è che sto facendo un sito di acquisti, quando l'utente aggiunge lo stesso prodotto in aggiunta al carrello ho bisogno di aggiornare la quantità solo –

+0

@AraviS Ho aggiornato la mia risposta con commenti. Accumulare quantità per lo stesso prodotto è un modello abbastanza comune. Nel trading puoi avere quantità negative;) –

0

In questo esempio vorrei utilizzare una mappa. Vediamo perché:

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

stessa firma metodo sarebbe ok.Ora, la differenza

//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()); 

spero che aiuta

0

Nel codice, se si utilizza "per ogni" dichiarazione del genere, un elemento della lista ha sempre una volta che la si confronta con se stesso e questo darà il risultato sbagliato. Si dovrebbe usare indice per accedere agli elementi della lista

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

e rememeber di rimuovere l'elemento duplicato utilizzando list.remove (indexOfTheDuplicate), list.clear() rimuoverà tutti gli elementi della lista.

0

È possibile modificare l'approccio per restituire un nuovo elenco con i dati necessari.

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; 
} 

In questo modo è possibile avere l'elenco originale e quello nuovo.