2017-06-20 11 views
4

hoffe jemand kann mir helfen. Ich habe eine POJO mit folgenden Struktur:Stream einer verschachtelten POJOs-Liste zu einer anderen POJO-LISTE

public class Invoice{ 

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

/* Getters and setters*/ 
} 

Und ein weiteres POJO mit folgenden

public class InvoiceDetails{ 

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

/* Getters and setters*/ 
} 

Außerdem habe ich eine dritter mit den folgenden

public class VatType{ 

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

/* Getters and setters*/ 
} 

habe Was ich versuche zu tun ist, eine List von Invoice zu einer ListVatType gruppiert von VatGroup zu reduzieren. Wie de DISTINCT Klausel in SQL. Sagen wir, ich habe folgende Liste:

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

Wie kann ich diese Liste eine stream in einem Schuss mit:

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

Das erwartete Ergebnis eine List von VatType mit den folgenden Elementen sein würde. Vermeiden Sie die Iteration durch die Lists? Vielen Dank im Voraus

+0

Haben Sie die Stream-API überprüft? – Pelocho

+1

Kann es eine gute Idee sein, die gemeinsamen Teile aus 'InvoiceDetailes' und' VatType' in eine 'CommonClass' zu extrahieren, dann können Sie Operationen auf' List ' ausführen und müssen Listen nicht umgekehrt umwandeln? –

Antwort

2

Sie zunächst ein flatMap benötigen einen Strom von allen InvoiceDetails in allen Invoice in Ihrer Liste zu erstellen. Danach können Sie mit der Variante , die eine Merge-Methode bekommt, reduzieren. Schließlich values() Verfahren von Map erhalten eine Collection von 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(); 

Wo dies VatType Konstruktor verwendet wird:

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

Sie leicht eine List von einem Collection machen kann, wenn man einen braucht:

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

Danke Manos, es funktioniert ziemlich gut !. – pburgov

1

Sie können Java-Stream-Funktion verwenden:

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

und dann Strom als die Verwendung von:

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

Danke ΦXocę 웃 Пepeúpa Es funktioniert gut, aber es nicht die Werte _merge_. – pburgov

0

Sie auch dozer library verwenden können, wenn diese gemeinsame Aufgabe in Ihrem Projekt.

1

Hier ist ein Weg, um es mit Hilfe von Java 8 der neuen Funktionen von List und Map, ohne Strömen zu tun:

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

Wenn Sie einen Konstruktor VatType hinzufügen könnten, die eine InvoiceDetail Instanz und eine merge Methode, die zwei verbindet akzeptiert VatType Instanzen:

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

Dann könnten Sie den ersten Schnipsel vereinfachen:

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

Danke Federico Es ist eine sehr interessante Alternative zu den Bächen. – pburgov

Verwandte Themen