J'ai un cours

public class ProductStock {

   private Long id;
   private Integer quantity;

}

Et une liste comme

List<ProductStock> productStocks = 
{
  ProductStock(1, 1),
  ProductStock(2, 1),
  ProductStock(3, 1),
  ProductStock(1, 1),
  ProductStock(4, 1),
  ProductStock(5, 1),
  ProductStock(2, 1)
}

Je souhaite regrouper les produits par identifiant. Quelle est la meilleure façon de convertir cette liste comme ci-dessous

productStocks = 
{
  ProductStock(1, 2),
  ProductStock(2, 2),
  ProductStock(3, 1),
  ProductStock(4, 1),
  ProductStock(5, 1)
}
4
Md. Shougat Hossain 16 nov. 2017 à 15:38

4 réponses

Meilleure réponse

Je le ferais de cette façon:

Map<Long, Integer> counting = productStocks.stream().collect(
                Collectors.groupingBy(ProductStock::getId, Collectors.counting()));

Créez une nouvelle carte avec l'id comme clé et le nombre comme valeur.

3
osanger 16 nov. 2017 à 12:41

Vous pouvez utiliser un Map pour regrouper tous les ProductStock en un seul endroit. Ensuite, vous pouvez utiliser le contenu de ce Map pour créer le nouveau List de ProductStock qui contiendra les données agrégées.

Map<Long, Long> productStockMap = productStocks.stream().collect(Collectors.groupingBy(ProductStock::getId, Collectors.counting()));
productStocks = new ArrayList<>();
for(Map.Entry<Long, Long> entry: productStockMap.entrySet()) {
    productStocks.add(new ProductStock(entry.getKey(), entry.getValue().intValue()));
}

Résultat:

============Before============

ProductStock{id=1, quantity=1}
ProductStock{id=2, quantity=1}
ProductStock{id=3, quantity=1}
ProductStock{id=1, quantity=1}
ProductStock{id=4, quantity=1}
ProductStock{id=5, quantity=1}
ProductStock{id=2, quantity=1}

=============After============

ProductStock{id=1, quantity=2}
ProductStock{id=2, quantity=2}
ProductStock{id=3, quantity=1}
ProductStock{id=4, quantity=1}
ProductStock{id=5, quantity=1}
1
Yash 16 nov. 2017 à 13:00

Vous pouvez regrouper les produits en itérant la liste et ajouter des produits à LinkedHashMap pour conserver l'ordre:

void mergeProducts() {
    Map<Long, Integer> pMap = new HashMap<Long, Integer>();
    for (ProductStock ps :  productStocks) {
        if (pMap.containsKey(ps.getId())) {
            int qty = pMap.get(ps.getId());
            qty += ps.getQuantity();
            pMap.put(ps.getId(), qty);
        } else {
            pMap.put(ps.getId(), ps.getQuantity());
        }
    }

    System.out.println("Product grouping: ");
    for (Map.Entry<Long, Integer> entry : pMap.entrySet()) {
        System.out.println(entry.getKey() + " " + entry.getValue());
    }
}
4
calvin.mk 16 nov. 2017 à 13:43

Avec les flux Java8, vous pouvez l'essayer comme ceci:

productStocks = new ArrayList<>( productStocks.stream().collect( 
       Collectors.toMap( p -> p.id, p -> p, (p,o) -> { p.quantity += o.quantity; return p;} ) )
                 .values() );

Ce que cela fait:

  • productStocks.stream().collect( Collectors.toMap(...) ) crée un flux pour la liste et collecte les valeurs dans une carte.
  • p -> p.id utilise l'identifiant du produit comme clé de mappage
  • p -> p utilise le produit comme valeur de la carte, s'il n'existe pas déjà
  • (p,o) -> { p.quantity += o.quantity; return p;} fusionne le produit existant p et la "nouvelle" valeur du produit o en ajoutant la quantité dans p et en la renvoyant. Vous pouvez également créer une nouvelle instance Product: (p,o) -> new Product(p.id, p.quantity + o.quantity)
  • enfin nous construisons une nouvelle liste à partir des valeurs de la carte

Notez que la collecte des éléments dans une carte comme like peut ne pas préserver l'ordre des éléments. Si vous souhaitez conserver l'ordre défini dans la liste source, vous pouvez ajouter un quatrième paramètre à collect(...): LinkedHashMap::new.

4
Thomas 16 nov. 2017 à 12:58
47329845