2017-01-13 17 views
5

Mam listę podatków:Grupa dwoma polami następnie zsumowanie BigDecimal

TaxLine = title:"New York Tax", rate:0.20, price:20.00 
TaxLine = title:"New York Tax", rate:0.20, price:20.00 
TaxLine = title:"County Tax", rate:0.10, price:10.00 

klasa TaxLine jest

public class TaxLine { 
    private BigDecimal price; 
    private BigDecimal rate; 
    private String title; 
} 

chciałbym je połączyć bazę na unikalnej title i rate, następnie dodać price, oczekiwano:

TaxLine = title:"New York Tax", rate:0.20, price:40.00 
TaxLine = title:"County Tax", rate:0.10, price:10.00 

Jak mogę to zrobić w Javie 8?

, nie sumuje pola, może grupować tylko według dwóch pól.

Odpowiedz

8

Głównym jest taka sama jak w połączonej pytanie, wystarczy inny kolektor dolną Podsumowując:

List<TaxLine> flattened = taxes.stream() 
    .collect(Collectors.groupingBy(
     TaxLine::getTitle, 
     Collectors.groupingBy(
      TaxLine::getRate, 
      Collectors.reducing(
       BigDecimal.ZERO, 
       TaxLine::getPrice, 
       BigDecimal::add)))) 
    .entrySet() 
    .stream() 
    .flatMap(e1 -> e1.getValue() 
     .entrySet() 
     .stream() 
     .map(e2 -> new TaxLine(e2.getValue(), e2.getKey(), e1.getKey()))) 
    .collect(Collectors.toList()); 
0

Nie można podsumować zgrupowanego pola można uzyskać, definiując nową klasę o nazwie TitleRate w klasie Taxline, jak poniżej.

class Taxline{ 
     public static class TitleRate { 
      public TitleRate(String title, int taxline) { 
       ... 
      } 

     } 

     public TitleRate getTitleRate() { 
      return new TitleRate(title, taxline); 
     } 
    } 

Aby zsumować cenę, grupując tytuł i stawkę podatku, można skorzystać z poniższego.

Map<TitleRate, List<Taxline>> groupedData = people.collect(Collectors.groupingBy(Taxline::getTitleRate)); 

    List<Taxline> groupedTaxLines = new ArrayList<Taxline>(); 
    BigDecimal groupedRate = BigDecimal.ZERO; 
    for (Map<TitleRate, List<Taxline>> entry : groupedData.entrySet()) 
    { 
    for(Taxline taxline : entry.getValue()){ 
     groupedRate = groupedRate.add(taxline.getPrice()); 
    } 
    groupedTaxLines.add(new Taxline(entry.getKey().getTitle, entry.getKey().getRate(), groupedRate)); 
     groupedRate = BigDecimal.ZERO; 
    } 
0

Jednym ze sposobów jest utworzenie obiektu dla zbioru pól, które grupujesz według. Ta klasa może być zbudowana w celu zapewnienia również dobrych metod pomocniczych.

Tak, z oryginalna klasa zakończone tak:

public final class TaxLine { 
    private String title; 
    private BigDecimal rate; 
    private BigDecimal price; 
    public TaxLine(String title, BigDecimal rate, BigDecimal price) { 
     this.title = title; 
     this.rate = rate; 
     this.price = price; 
    } 
    public String getTitle() { 
     return this.title; 
    } 
    public BigDecimal getRate() { 
     return this.rate; 
    } 
    public BigDecimal getPrice() { 
     return this.price; 
    } 
    @Override 
    public String toString() { 
     return "TaxLine = title:\"" + this.title + "\", rate:" + this.rate + ", price:" + this.price; 
    } 
} 

oraz grupowanie klasy pomocnika zdefiniowane następująco:

public final class TaxGroup { 
    private String title; 
    private BigDecimal rate; 
    public static TaxLine asLine(Entry<TaxGroup, BigDecimal> e) { 
     return new TaxLine(e.getKey().getTitle(), e.getKey().getRate(), e.getValue()); 
    } 
    public TaxGroup(TaxLine taxLine) { 
     this.title = taxLine.getTitle(); 
     this.rate = taxLine.getRate(); 
    } 
    public String getTitle() { 
     return this.title; 
    } 
    public BigDecimal getRate() { 
     return this.rate; 
    } 
    @Override 
    public int hashCode() { 
     return this.title.hashCode() * 31 + this.rate.hashCode(); 
    } 
    @Override 
    public boolean equals(Object obj) { 
     if (obj == null || getClass() != obj.getClass()) 
      return false; 
     TaxGroup that = (TaxGroup) obj; 
     return (this.title.equals(that.title) && this.rate.equals(that.rate)); 
    } 
} 

Twój kod do łączonych elementów liniowych jest to, podzielony na wiele linie pomóc zobaczyć jego poszczególnych części:

List<TaxLine> lines = Arrays.asList(
     new TaxLine("New York Tax", new BigDecimal("0.20"), new BigDecimal("20.00")), 
     new TaxLine("New York Tax", new BigDecimal("0.20"), new BigDecimal("20.00")), 
     new TaxLine("County Tax" , new BigDecimal("0.10"), new BigDecimal("10.00")) 
); 
List<TaxLine> combined = 
     lines 
     .stream() 
     .collect(Collectors.groupingBy(TaxGroup::new, 
             Collectors.reducing(BigDecimal.ZERO, 
                  TaxLine::getPrice, 
                  BigDecimal::add))) 
     .entrySet() 
     .stream() 
     .map(TaxGroup::asLine) 
     .collect(Collectors.toList()); 

następnie można wydrukować wejścia/wyjścia:

System.out.println("Input:"); 
lines.stream().forEach(System.out::println); 
System.out.println("Combined:"); 
combined.stream().forEach(System.out::println); 

Aby to produkować:

Input: 
TaxLine = title:"New York Tax", rate:0.20, price:20.00 
TaxLine = title:"New York Tax", rate:0.20, price:20.00 
TaxLine = title:"County Tax", rate:0.10, price:10.00 
Combined: 
TaxLine = title:"New York Tax", rate:0.20, price:40.00 
TaxLine = title:"County Tax", rate:0.10, price:10.00