2017-06-20 1 views
4

J'espère que quelqu'un pourra m'aider. J'ai un POJO avec la structure suivante:Flux d'une liste de POJO imbriqués vers une autre liste de POJO

public class Invoice{ 

private String docNum; 
private String customer; 
private ArrayList<InvoiceDetails> invoiceDetails; 

/* Getters and setters*/ 
} 

Et une autre POJO avec les éléments suivants

public class InvoiceDetails{ 

private String vatGroup; 
private Double vatAmount; 
private Double amount; 

/* Getters and setters*/ 
} 

D'ailleurs, j'ai un troisième avec le

suivant
public class VatType{ 

private String vatGroup; 
private Double vatAmount; 
private Double amount; 

/* Getters and setters*/ 
} 

Ce que je suis en train faire est de réduire un List de Invoice à un List de VatType groupé par vatGroup. Comme de DISTINCT clause dans SQL. Disons que j'ai la liste suivante:

InvoiceDetails idA1 = new InvoiceDetails("S1", 100.0, 40.0); 
InvoiceDetails idA2 = new InvoiceDetails("S2", 140.0, 40.0); 
InvoiceDetails idA3 = new InvoiceDetails("A1", 50.0, 10.0); 
ArrayList<InvoiceDetails> listA = new ArrayList<>(); 
listA.add(idA1); 
listA.add(idA2); 
listA.add(idA3); 

Invoice invoiceA = new Invoice(); 
invoiceA.setDetailList(listA); 

InvoiceDetails idB1 = new InvoiceDetails("S1", 200.0, 50.0); 
InvoiceDetails idB2 = new InvoiceDetails("S2", 240.0, 50.0); 
InvoiceDetails idB2 = new InvoiceDetails("A1", 100.0, 20.0); 
ArrayList<InvoiceDetails> listB = new ArrayList<>(); 
listB.add(idB1); 
listB.add(idB2); 
listB.add(idB3); 


Invoice invoiceB = new Invoice(); 
invoiceB.setDetailList(listB); 

List<Invoice> invoiceList = new ArrayList<>(); 
invoiceList.add(invoiceA); 
invoiceList.add(invoiceB); 

Le résultat attendu serait un List de VatType avec les éléments suivants:

("S1",300.0,90.0) 
("S2",380.0,90.0) 
("A1",150.0,30.0) 

Comment puis-je obtenir cette liste en utilisant un stream en un seul coup. Éviter de parcourir le Lists? Merci à l'avance

+0

Avez-vous vérifié l'API Stream? – Pelocho

+1

Peut-être une bonne idée d'extraire les parties communes de 'InvoiceDetailes' et' VatType' dans un 'CommonClass', alors vous pouvez faire des opérations sur' Liste 'et ne pas avoir à convertir les listes vica-versa? –

Répondre

2

d'abord vous aurez besoin d'un flatMap pour créer un flux de tous InvoiceDetails dans tous Invoice dans votre liste. Après cela, vous pouvez réduire avec la variante de toMap qui obtient une méthode de fusion. Enfin méthode values() de Map obtiendra un Collection de VatType:

Collection<VatType> values = invoiceList.stream() 
     .flatMap(invoices -> invoices.getInvoiceDetails().stream()) 
     .collect(toMap(InvoiceDetails::getVatGroup, VatType::new, (i1, i2) -> { 
      i1.setAmount(i1.getAmount() + i2.getAmount()); 
      i1.setVatAmount(i1.getVatAmount() + i2.getVatAmount()); 
      return i1; 
     })) 
     .values(); 

Si ce constructeur VatType est utilisé:

VatType(InvoiceDetails invoiceDetails) { 
    vatGroup = invoiceDetails.getVatGroup(); 
    vatAmount = invoiceDetails.getVatAmount(); 
    amount = invoiceDetails.getAmount(); 
} 

Vous pouvez facilement faire une List d'un Collection si vous en avez besoin:

List<VatType> vatTypes = new ArrayList<>(values); 
+0

Merci Manos, ça marche plutôt bien! – pburgov

1

Vous pouvez utiliser le flux Java Fonction:

Function<InvoiceDetails, VatType> myF = t -> new VatType(t.getVatGroup(), t.getVatAmount(), t.getAmount()); 

puis flux que d'utiliser:

List<VatType> myLocations = 
     invoiceList.stream() 
     .map(Invoice::getInvoiceDetails) 
     .flatMap(Collection::stream) 
     .map(myF) 
     .collect(Collectors.<VatType>toList()); 
+0

Merci ΦXocę 웃 Пepeúpa Ça fonctionne bien, il ne fait pas _merge_ les valeurs. – pburgov

0

Vous pouvez également utiliser dozer library si cela est une tâche commune dans votre projet.

1

Voici une façon de le faire en utilisant les nouvelles fonctionnalités de Java 8 de List et Map, sans cours d'eau:

Map<String, VatType> map = new HashMap<>(); 

invoiceList.forEach(i -> i.getDetailList().forEach(d -> 
    map.merge(
     d.getVatGroup(), 
     new VatType(d.getVatGroup(), d.getVatAmount(), d.getAmount()), 
     (left, right) -> { 
      left.setAmount(left.getAmount() + right.getAmount()); 
      left.setVatAmount(left.getVatAmount() + right.getVatAmount()); 
      return left; 
     }))); 

List<VatType> result = new ArrayList<>(map.values()); 

Si vous pouvez ajouter un constructeur à VatType qui accepte une instance InvoiceDetail et une méthode merge qui combine deux VatType instances:

public VatType(String vatGroup, Double vatAmount, Double amount) { 
    this.vatGroup = vatGroup; 
    this.vatAmount = vatAmount; 
    this.amount = amount; 
} 

public VatType(InvoiceDetails details) { 
    this(details.getVatGroup(), details.getVatAmount(), details.getAmount()); 
} 

public VatType merge(VatType another) { 
    this.vatAmount += another.vatAmount; 
    this.amount += another.amount; 
    return this; 
} 

Ensuite, vous pouvez simplifier le premier extrait à:

Map<String, VatType> map = new HashMap<>(); 

invoiceList.forEach(i -> i.getDetailList().forEach(d -> 
     map.merge(d.getVatGroup(), new VatType(d), VatType::merge))); 

List<VatType> result = new ArrayList<>(map.values()); 
+1

Merci Federico C'est une alternative très intéressante aux flux. – pburgov