Adding Up Bigdecimals Using Streams

Adding up BigDecimals using Streams

Original answer

Yes, this is possible:

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

What it does is:

  1. Obtain a List<BigDecimal>.
  2. Turn it into a Stream<BigDecimal>
  3. Call the reduce method.

    3.1. We supply an identity value for addition, namely BigDecimal.ZERO.

    3.2. We specify the BinaryOperator<BigDecimal>, which adds two BigDecimal's, via a method reference BigDecimal::add.

Updated answer, after edit

I see that you have added new data, therefore the new answer will become:

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

It is mostly the same, except that I have added a totalMapper variable, that has a function from Invoice to BigDecimal and returns the total price of that invoice.

Then I obtain a Stream<Invoice>, map it to a Stream<BigDecimal> and then reduce it to a BigDecimal.

Now, from an OOP design point I would advice you to also actually use the total() method, which you have already defined, then it even becomes easier:

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

Here we directly use the method reference in the map method.

Sum BigDecimal values in List with lambda

It is quite easy with a Stream and a reducer :

BigDecimal sum = simples
.stream()
.map(Simple::getAmount)
.reduce(BigDecimal::add)
.get();

Grouping and adding up BigDecimals using Java Stream API

Simplest solution would be using Collectors::toMap including the merge function.

Map<IncomeType, BigDecimal> grouping = incomes.stream()
.collect(Collectors.toMap(Income::getType, Income::getAmount, BigDecimal::add));

Summing up BigDecimal in a map of list of objects in Java

  1. Stream the values of the Map.
  2. Use flatMap to flatten the stream of lists of BigDecimals to a stream of BigDecimals.
  3. Use map to extract the BigDecimals.
  4. Use reduce with a summing operation.
BigDecimal sum = myMap.values().stream()
.flatMap(List::stream)
.map(Obj::getB)
.reduce(BigDecimal.ZERO, (a, b) -> a.add(b) );

The Stream.reduce method takes an identity value (for summing values, zero), and a BinaryOperator that adds intermediate results together.

You may also use a method reference in place of the lambda above: BigDecimal::add.

sum of BigDecimal List using streams and sum method

List<BigDecimal> items = Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(1.5), BigDecimal.valueOf(100));
items.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

Though Answer provided by Lisq199 works but I am in favor of including Holger and Klitos comments,This handles No values and always returns a value

Adding BigDecimal in Stream using reduce method

Map to big decimal stream then reduce

BigDecimal op = orderPositions
.stream()
.filter(orderPosition -> Category.A.equals(orderPosition.getProduct().getCategory()))
.map(orderPosition1 -> orderPosition1.getProduct().getPrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);

Link:
https://mkyong.com/java8/java-8-how-to-sum-bigdecimal-using-stream/
The first value(BigDecimal.ZERO) is the default value in case stream is empty

Note that I also change to equal order of the Enum, to avoid nullPointerException

How to average BigDecimals using Streams?

BigDecimal[] totalWithCount
= bigDecimals.stream()
.filter(bd -> bd != null)
.map(bd -> new BigDecimal[]{bd, BigDecimal.ONE})
.reduce((a, b) -> new BigDecimal[]{a[0].add(b[0]), a[1].add(BigDecimal.ONE)})
.get();
BigDecimal mean = totalWithCount[0].divide(totalWithCount[1], roundingMode);

Optional text description of the code for those that are find that to be helpful (Ignore if you find the code sufficiently self explanatory.):

  • The list of BigDecimals is converted to a stream.
  • null values are filtered out of the stream.
  • The stream of BigDecimals is mapped to as stream of two element arrays of BigDecimal where the first element is the element from the original stream and the second is the place holder with value one.
  • In the reduce the a of (a,b) value has the partial sum in the first element and the partial count in the second element. The first element of the b element contains each of the BigDecimal values to add to the sum. The second element of b is not used.
  • Reduce returns an optional that will be empty if the list was empty or contained only null values.

    • If the Optional is not empty, Optional.get() function will return a two element array of BigDecimal where the sum of the BigDecimals is in the first element and the count of the BigDecimals is in the second.
    • If the Optional is empty, NoSuchElementException will be thrown.
  • The mean is computed by dividing the sum by the count.

How to convert Long to BigDecimal while also using a Stream

The most simple and efficient way to do is to use terminal operation count() which returns the number of elements in the stream as long and then convert into BigDecimal:

stat.setCount_human_dna(getDNACount(dnaSamples));
public static BigDecimal getDNACount(Collection<Sample> dnaSamples) {
long humanSamples = dnaSamples.stream()
.filter(x -> x.getType().equals("Human"))
.count();

return BigDecimal.valueOf(humanSamples);
}

And you can produce the result of type BigDecimal directly from the stream using reduce() a terminal operation:

stat.setCount_human_dna(getDNACount(dnaSamples));
public static BigDecimal getDNACount(Collection<Sample> dnaSamples) {
return dnaSamples.stream()
.filter(x -> x.getType().equals("Human"))
.reduce(BigDecimal.ZERO,
(total, next) -> total.add(BigDecimal.ONE),
BigDecimal::add);
}

Sidenote: I'm not an expert in such questions as DNA analysis, but the result of this reduction will always be a whole number. You might consider utilizing BigInteger instead of BigDecimal.

Summing a map of doubles into an aggregated BigDecimal with Java Streams

You should add BigDecimals using BigDecimal.add() instead of converting them to double and back again to avoid rounding errors. To sum all prices you can use Stream.reduce():

BigDecimal bigDecimal = order.getOrderLines().stream()
.map(OrderLine::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);

From the docs of Stream.reduce():

Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. This is equivalent to:

T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;

BigDecimal::add is a short form of (a, b) -> a.add(b), which simply returns a + b. For addition the identity element is 0 or BigDecimal.ZERO.

Sum a list of objects based on BigDecimal field in single line

list.stream().map(foo -> foo.field).reduce(BigDecimal.ZERO, (a, b) -> a.add(b));


Related Topics



Leave a reply



Submit