SiriusBits
SiriusBits

Reputation: 800

Combine ArrayList of Objects and sum on BigDecimal in Java

I want to combine and sum (specific properties) of two ArrayList of identical Domain Objects. Based on the condition of multiple properties matching, then combine them in one.

Here is my model class

public class SalesTransactionTax {

  private String code;
  private BigDecimal rate;
  private Boolean isFixed;
  private BigDecimal taxAmount;

  public SalesTransactionTax(String code, BigDecimal rate, Boolean isFixed, BigDecimal taxAmount) { // NO_UCD
                                                                                                    // (unused
    // code)

    this.code = code;
    this.rate = rate;
    this.isFixed = isFixed;
    this.taxAmount = taxAmount;
  }

  public SalesTransactionTax() {

  }

  public String getCode() {

    return code;
  }

  public void setCode(String code) {

    this.code = code;
  }

  public BigDecimal getRate() {

    return rate;
  }

  public void setRate(BigDecimal rate) {

    this.rate = rate;
  }

  public Boolean getIsFixed() {

    return isFixed;
  }

  public void setFixed(Boolean fixed) {

    isFixed = fixed;
  }

  public BigDecimal getTaxAmount() {
    return taxAmount;
  }

  public void setTaxAmount(BigDecimal taxAmount) {
    this.taxAmount = taxAmount;
  }

  @Override
  public String toString() {
    return "SalesTransactionTax [code=" + code + ", rate=" + rate + ", isFixed=" + isFixed
        + ", taxAmount=" + taxAmount + "]";
  }

}

Using the following as an example:

List<SalesTransactionTax> taxes  = new ArrayList<>();

taxes.add(new SalesTransactionTax("VAT_1", 5.000, true, 1.100));
taxes.add(new SalesTransactionTax("VAT_1", 5.000, true, 1.100));
taxes.add(new SalesTransactionTax("VAT_2", 9.000, true, 2.200));
taxes.add(new SalesTransactionTax("VAT_2", 9.000, true, 2.200));
taxes.add(new SalesTransactionTax("VAT_2", 9.000, true, 2.200));
taxes.add(new SalesTransactionTax("VAT_2", 9.000, false, 9.500));
taxes.add(new SalesTransactionTax("VAT_3", 7.000, true, 1.000));

Values in a new ArrayList would be:

Using Java 8, maybe a Lambda expression would be the way to go? Thanks for any suggestions.

Upvotes: 1

Views: 1069

Answers (2)

JUAN CALVOPINA M
JUAN CALVOPINA M

Reputation: 3974

The add (...) method should has the logic to sum the taxes amount, for to do that, it is necessary to check if the new transaction complies with established validations.

The validations should has the same: getCode(), getRate(), getIsFixed()

Snippet code to add:

public void add(SalesTransactionTax inputValue) {
    SalesTransactionTax salesTransactionTax = checkInList(inputValue);
    if (salesTransactionTax != null) {
        // To sum operations the method used is add() from BigDecimal
        salesTransactionTax.setTaxAmount(salesTransactionTax.getTaxAmount().add(inputValue.getTaxAmount()));
    } else {
        this.salesTransactionTaxList.add(inputValue);
    }
}

To check if exist the new SalesTransactionTax in the list you can validate using filter() method from Java 8

Snippet code to check the validations:

private SalesTransactionTax checkInList(SalesTransactionTax stt) {
    return salesTransactionTaxList.stream()
            // To compare String is used equals()
            .filter(stt2 -> stt2.getCode().equals(stt.getCode()))
            // To compare BigDecimal is used compareTo()
            .filter(stt2 -> stt2.getRate().compareTo(stt.getRate()) == 0)
            // To compare boolean is used ==
            .filter(stt2 -> stt2.getIsFixed() == stt.getIsFixed())
            // If doesn't exist return null
            .findAny().orElse(null);
}

Full example:

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class SalesTransactionTax {

    private String code;
    private BigDecimal rate;
    private Boolean isFixed;
    private BigDecimal taxAmount;
    private List<SalesTransactionTax> salesTransactionTaxList = null;

    public SalesTransactionTax(String code, BigDecimal rate, Boolean isFixed, BigDecimal taxAmount) { // NO_UCD
        this.code = code;
        this.rate = rate;
        this.isFixed = isFixed;
        this.taxAmount = taxAmount;
    }

    public SalesTransactionTax() {
        this.salesTransactionTaxList = new ArrayList<>();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public BigDecimal getRate() {
        return rate;
    }

    public void setRate(BigDecimal rate) {
        this.rate = rate;
    }

    public Boolean getIsFixed() {
        return isFixed;
    }

    public void setFixed(Boolean fixed) {
        isFixed = fixed;
    }

    public BigDecimal getTaxAmount() {
        return taxAmount;
    }

    public void setTaxAmount(BigDecimal taxAmount) {
        this.taxAmount = taxAmount;
    }

    public void add(SalesTransactionTax inputValue) {
        SalesTransactionTax salesTransactionTax = checkInList(inputValue);
        if (salesTransactionTax != null) {
            // To sum operations the method used is add() from BigDecimal
            salesTransactionTax.setTaxAmount(salesTransactionTax.getTaxAmount().add(inputValue.getTaxAmount()));
        } else {
            this.salesTransactionTaxList.add(inputValue);
        }
    }

private SalesTransactionTax checkInList(SalesTransactionTax stt) {
    return salesTransactionTaxList.stream()
            // To compare String is used equals()
            .filter(stt2 -> stt2.getCode().equals(stt.getCode()))
            // To compare BigDecimal is used compareTo()
            .filter(stt2 -> stt2.getRate().compareTo(stt.getRate()) == 0)
            // To compare boolean is used ==
            .filter(stt2 -> stt2.getIsFixed() == stt.getIsFixed())
            // If doesn't exist return null
            .findAny().orElse(null);
}

    public void print() {
        salesTransactionTaxList.forEach(System.out::println);
    }

    @Override
    public String toString() {
        //Output formatted
        DecimalFormat df = new DecimalFormat("#,###.000");
        return code + ", " + df.format(new BigDecimal(String.valueOf(rate))) + ", " + isFixed + ", " + df.format(new BigDecimal(String.valueOf(taxAmount)));
    }

    public static void main(String[] args) {

        SalesTransactionTax mergeTaxes = new SalesTransactionTax();
        mergeTaxes.add(new SalesTransactionTax("VAT_1", BigDecimal.valueOf(5.000), true, BigDecimal.valueOf(1.100)));
        mergeTaxes.add(new SalesTransactionTax("VAT_1", BigDecimal.valueOf(5.000), true, BigDecimal.valueOf(1.100)));
        mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
        mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
        mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
        mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), false, BigDecimal.valueOf(9.500)));
        mergeTaxes.add(new SalesTransactionTax("VAT_3", BigDecimal.valueOf(7.000), true, BigDecimal.valueOf(1.000)));
        mergeTaxes.print();
    }

}

Output:

VAT_1, 5.000, true, 2.200
VAT_2, 9.000, true, 6.600
VAT_2, 9.000, false, 9.500
VAT_3, 7.000, true, 1.000

Upvotes: 4

shop350
shop350

Reputation: 208

You said

Based on the condition if two properties match, then combine them in one.

But based on the example results, you need to check three properties match.

public class SalesTransactionMerge {

private List<SalesTransactionTax> taxes = null;

public List<SalesTransactionTax> getTaxes(){
    return this.taxes;
}

public SalesTransactionMerge(){
    this.taxes = new ArrayList<SalesTransactionTax>();
}

public void add(SalesTransactionTax stt){
    SalesTransactionTax sttExists = exists(stt);
    if(sttExists == null){
        this.taxes.add(stt);
    }
    else{
        sttExists.setTaxAmount(sttExists.getTaxAmount().add(stt.getTaxAmount()));
    }
}

private SalesTransactionTax exists(SalesTransactionTax stt){
    SalesTransactionTax sttExists = null;
    for(SalesTransactionTax stt2 : taxes){
        int matches = 0;
        if(stt2.getCode().equals(stt.getCode())) matches++;
        if(stt2.getRate().compareTo(stt.getRate()) == 0) matches++;
        if(stt2.getIsFixed() == stt.getIsFixed()) matches++;
        if(matches == 3){       
            sttExists = stt2;
            break;
        }
    }
    return sttExists;
}

public void print(){
    for(SalesTransactionTax stt : taxes){
        System.out.println(stt.toString());
    }
}
}

Using your examples

public static void main(String[] args) {

    SalesTransactionMerge mergeTaxes = new SalesTransactionMerge();
    mergeTaxes.add(new SalesTransactionTax("VAT_1", BigDecimal.valueOf(5.000), true, BigDecimal.valueOf(1.100)));
    mergeTaxes.add(new SalesTransactionTax("VAT_1", BigDecimal.valueOf(5.000), true, BigDecimal.valueOf(1.100)));
    mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
    mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
    mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), true, BigDecimal.valueOf(2.200)));
    mergeTaxes.add(new SalesTransactionTax("VAT_2", BigDecimal.valueOf(9.000), false, BigDecimal.valueOf(9.500)));
    mergeTaxes.add(new SalesTransactionTax("VAT_3", BigDecimal.valueOf(7.000), true, BigDecimal.valueOf(1.000)));
    mergeTaxes.print();
}

Upvotes: 0

Related Questions