programing

스트림을 사용한 BigDecimal 추가

goodsources 2022. 8. 30. 22:33
반응형

스트림을 사용한 BigDecimal 추가

Big Decimals 컬렉션이 있습니다(이 예에서는LinkedList추가하겠습니다.이거 스트림으로 할 수 있어요?

나는 알아차렸다.Stream클래스에는 몇 가지 메서드가 있습니다.

Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong

각각 편리한 점이 있다.sum()방법.하지만 알다시피float그리고.double산수는 거의 항상 나쁜 생각이다.

그렇다면, 빅 데코멘탈을 요약하는 편리한 방법이 있을까요?

이게 제가 지금까지 가지고 있는 암호입니다.

public static void main(String[] args) {
    LinkedList<BigDecimal> values = new LinkedList<>();
    values.add(BigDecimal.valueOf(.1));
    values.add(BigDecimal.valueOf(1.1));
    values.add(BigDecimal.valueOf(2.1));
    values.add(BigDecimal.valueOf(.1));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(BigDecimal value : values) {
        System.out.println(value);
        sum = sum.add(value);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    values.forEach((value) -> System.out.println(value));
    System.out.println("Sum = " + values.stream().mapToDouble(BigDecimal::doubleValue).sum());
    System.out.println(values.stream().mapToDouble(BigDecimal::doubleValue).summaryStatistics().toString());
}

보다시피, 저는 빅데모럴을 요약하고 있습니다.BigDecimal::doubleValue()(역시) 정확하지 않습니다.

후세를 위한 사후 응답 편집:

두 답변 모두 큰 도움이 되었습니다.조금 덧붙이고 싶은 것이 있습니다.실제 시나리오에서는 raw의 컬렉션은 포함되어 있지 않습니다.BigDecimals는 송장에 포장되어 있습니다.하지만, 나는 이것을 설명하기 위해 Aman Agnihotri의 답변을 수정할 수 있었습니다.map()스트림의 함수:

public static void main(String[] args) {

    LinkedList<Invoice> invoices = new LinkedList<>();
    invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
    invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
    invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
    invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(Invoice invoice : invoices) {
        BigDecimal total = invoice.unit_price.multiply(invoice.quantity);
        System.out.println(total);
        sum = sum.add(total);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    invoices.forEach((invoice) -> System.out.println(invoice.total()));
    System.out.println("Sum = " + invoices.stream().map((x) -> x.total()).reduce((x, y) -> x.add(y)).get());
}

static class Invoice {
    String company;
    String invoice_number;
    BigDecimal unit_price;
    BigDecimal quantity;

    public Invoice() {
        unit_price = BigDecimal.ZERO;
        quantity = BigDecimal.ZERO;
    }

    public Invoice(String company, String invoice_number, BigDecimal unit_price, BigDecimal quantity) {
        this.company = company;
        this.invoice_number = invoice_number;
        this.unit_price = unit_price;
        this.quantity = quantity;
    }

    public BigDecimal total() {
        return unit_price.multiply(quantity);
    }

    public void setUnit_price(BigDecimal unit_price) {
        this.unit_price = unit_price;
    }

    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
    }

    public void setInvoice_number(String invoice_number) {
        this.invoice_number = invoice_number;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public BigDecimal getUnit_price() {
        return unit_price;
    }

    public BigDecimal getQuantity() {
        return quantity;
    }

    public String getInvoice_number() {
        return invoice_number;
    }

    public String getCompany() {
        return company;
    }
}

원답

네, 가능합니다.

List<BigDecimal> bdList = new ArrayList<>();
//populate list
BigDecimal result = bdList.stream()
        .reduce(BigDecimal.ZERO, BigDecimal::add);

기능:

  1. 를 입수하다List<BigDecimal>.
  2. 로 변환합니다.Stream<BigDecimal>
  3. reduce 메서드를 호출합니다.

    3.1. 델은 추가를 위해 ID 값을 제공합니다.즉,BigDecimal.ZERO.

    3.2. 다음 조건을 지정합니다.BinaryOperator<BigDecimal>2개의 추가가 있습니다.BigDecimal의, 메서드 레퍼런스에 의한BigDecimal::add.

편집 후 답변 업데이트

새로운 데이터를 추가했으므로 새로운 답변은 다음과 같습니다.

List<Invoice> invoiceList = new ArrayList<>();
//populate
Function<Invoice, BigDecimal> totalMapper = invoice -> invoice.getUnit_price().multiply(invoice.getQuantity());
BigDecimal result = invoiceList.stream()
        .map(totalMapper)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

거의 똑같아. 다만, 내가 한 번 더했다.totalMappervariable, from function이 있는 변수Invoice로.BigDecimal그리고 그 청구서의 총 가격을 반환합니다.

그 후, 저는Stream<Invoice>, 에 매핑합니다.Stream<BigDecimal>그리고 나서 그것을 a로 줄인다.BigDecimal.

OOP 설계 관점에서, 저는 당신에게 실제로 사용하기를 권합니다.total()이미 정의되어 있는 방법을 사용하면, 한층 더 간단하게 할 수 있습니다.

List<Invoice> invoiceList = new ArrayList<>();
//populate
BigDecimal result = invoiceList.stream()
        .map(Invoice::total)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

여기서는 의 메서드레퍼런스를 직접 사용합니다.map방법.

이 게시물에는 이미 체크된 답변이 있지만 답변이 null 값을 필터링하지 않습니다.정답은 Object:: non Null 함수를 술어로 사용하여 null 값을 방지해야 합니다.

BigDecimal result = invoiceList.stream()
    .map(Invoice::total)
    .filter(Objects::nonNull)
    .filter(i -> (i.getUnit_price() != null) && (i.getQuantity != null))
    .reduce(BigDecimal.ZERO, BigDecimal::add);

이것에 의해, null 값이 감소했을 때에 합계되는 것을 막을 수 있습니다.

의 값을 요약할 수 있습니다.BigDecimal resuableCollector를 사용한 스트림 이름summingUp:

BigDecimal sum = bigDecimalStream.collect(summingUp());

Collector다음과 같이 실장할 수 있습니다.

public static Collector<BigDecimal, ?, BigDecimal> summingUp() {
    return Collectors.reducing(BigDecimal.ZERO, BigDecimal::add);
}

Big Decimal 목록을 집계하려면 다음 방법을 사용합니다.

List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce((x, y) -> x.add(y)).get();

이 접근법에서는 각 BigDecimal을 BigDecimal로만 매핑하고 합계함으로써 이들을 줄입니다.이러한 어프로치에서는 다음 명령어를 사용하여 반환됩니다.get()★★★★★★ 。

다음은 동일한 합계를 수행하는 또 다른 간단한 방법입니다.

List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce(BigDecimal::add).get();

갱신하다

만약 편집된 질문에 수업과 람다 표현을 쓴다면 다음과 같이 쓸 것입니다.

import java.math.BigDecimal;
import java.util.LinkedList;

public class Demo
{
  public static void main(String[] args)
  {
    LinkedList<Invoice> invoices = new LinkedList<>();
    invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
    invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
    invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
    invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));

    // Java 8 approach, using Method Reference for mapping purposes.
    invoices.stream().map(Invoice::total).forEach(System.out::println);
    System.out.println("Sum = " + invoices.stream().map(Invoice::total).reduce((x, y) -> x.add(y)).get());
  }

  // This is just my style of writing classes. Yours can differ.
  static class Invoice
  {
    private String company;
    private String number;
    private BigDecimal unitPrice;
    private BigDecimal quantity;

    public Invoice()
    {
      unitPrice = quantity = BigDecimal.ZERO;
    }

    public Invoice(String company, String number, BigDecimal unitPrice, BigDecimal quantity)
    {
      setCompany(company);
      setNumber(number);
      setUnitPrice(unitPrice);
      setQuantity(quantity);
    }

    public BigDecimal total()
    {
      return unitPrice.multiply(quantity);
    }

    public String getCompany()
    {
      return company;
    }

    public void setCompany(String company)
    {
      this.company = company;
    }

    public String getNumber()
    {
      return number;
    }

    public void setNumber(String number)
    {
      this.number = number;
    }

    public BigDecimal getUnitPrice()
    {
      return unitPrice;
    }

    public void setUnitPrice(BigDecimal unitPrice)
    {
      this.unitPrice = unitPrice;
    }

    public BigDecimal getQuantity()
    {
      return quantity;
    }

    public void setQuantity(BigDecimal quantity)
    {
      this.quantity = quantity;
    }
  }
}

서드파티의 의존관계에 개의치 않는 경우, Eclipse Collections에는 Collectors2라는 클래스가 있습니다.이 클래스에는 BigDecimal과 BigInteger의 합계위해 Collectors를 반환하는 메서드가 포함되어 있습니다.이러한 메서드는 함수(Function)를 파라미터로 사용하여 객체에서 BigDecimal 또는 BigInteger 값을 추출할 수 있습니다.

List<BigDecimal> list = mList(
        BigDecimal.valueOf(0.1),
        BigDecimal.valueOf(1.1),
        BigDecimal.valueOf(2.1),
        BigDecimal.valueOf(0.1));

BigDecimal sum =
        list.stream().collect(Collectors2.summingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), sum);

BigDecimalSummaryStatistics statistics =
        list.stream().collect(Collectors2.summarizingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), statistics.getSum());
Assert.assertEquals(BigDecimal.valueOf(0.1), statistics.getMin());
Assert.assertEquals(BigDecimal.valueOf(2.1), statistics.getMax());
Assert.assertEquals(BigDecimal.valueOf(0.85), statistics.getAverage());

주의: 저는 Eclipse Collections의 커밋입니다.

언급URL : https://stackoverflow.com/questions/22635945/adding-up-bigdecimals-using-streams

반응형