Group by two fields then summing BigDecimal

后端 未结 3 965
轮回少年
轮回少年 2021-02-04 11:19

I have a list of taxes:

TaxLine = title:\"New York Tax\", rate:0.20, price:20.00
TaxLine = title:\"New York Tax\", rate:0.20, price:20.00
TaxLine = title:\"Count         


        
3条回答
  •  梦毁少年i
    2021-02-04 11:58

    One way is to create an object for the set of fields you're grouping by. That class can be built to provide nice helper methods too.

    So, with your original class completed like this:

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

    And the grouping helper class defined like this:

    public final class TaxGroup {
        private String title;
        private BigDecimal rate;
        public static TaxLine asLine(Entry 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));
        }
    }
    

    Your code to combined the line items is this, split over many lines to help see its various parts:

    List 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 combined =
            lines
            .stream()
            .collect(Collectors.groupingBy(TaxGroup::new,
                                           Collectors.reducing(BigDecimal.ZERO,
                                                               TaxLine::getPrice,
                                                               BigDecimal::add)))
            .entrySet()
            .stream()
            .map(TaxGroup::asLine)
            .collect(Collectors.toList());
    

    You can then print input/output:

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

    To produce this:

    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
    

提交回复
热议问题