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:
- Obtain a
List<BigDecimal>
. - Turn it into a
Stream<BigDecimal>
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 twoBigDecimal
's, via a method referenceBigDecimal::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
- Stream the values of the
Map
. - Use
flatMap
to flatten the stream of lists ofBigDecimal
s to a stream ofBigDecimal
s. - Use
map
to extract theBigDecimal
s. - 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 theb
element contains each of the BigDecimal values to add to the sum. The second element ofb
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 BigDecimal
s 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
Override Default Spring-Boot Application.Properties Settings in Junit Test
How to Combine Two Hashmap Objects Containing the Same Types
Java: How to Access Methods from Another Class
Do Hibernate Table Classes Need to Be Serializable
Java.Lang.Classcastexception Using Lambda Expressions in Spark Job on Remote Server
Dependency Injection in Struts2 Accessing Session Scoped Beans
Static VS. Dynamic Binding in Java
Java.Util.Stream with Resultset
Java Generics: Generic Type Defined as Return Type Only
Convert Base64 String to Image
Case Insensitive String as Hashmap Key
Difference Between Java.Exe and Javaw.Exe
How to Unmap a File from Memory Mapped Using Filechannel in Java