How to collect two sum from a stream in Java 8 - java

class Stock{
double profit;
double profitPercentage;
public double getProfit(){
return profit;
}
public double getProfitPercentage(){
return profitPercentage;
}
}
List<Stock> stocks = getAllStocks();
stocks.stream.collect(Collectors.summarizingDouble(Stock:getProfit)).getSum();
stocks.stream.collect(Collectors.summarizingDouble(Stock:getProfitPercentage)).getSum();
I could not find out way to do in single pass of stream. Any help or pointer would be good.

The straight-forward way is to create a custom collector class.
public class StockStatistics {
private DoubleSummaryStatistics profitStat = new DoubleSummaryStatistics();
private DoubleSummaryStatistics profitPercentageStat = new DoubleSummaryStatistics();
public void accept(Stock stock) {
profitStat.accept(stock.getProfit());
profitPercentageStat.accept(stock.getProfitPercentage());
}
public StockStatistics combine(StockStatistics other) {
profitStat.combine(other.profitStat);
profitPercentageStat.combine(other.profitPercentageStat);
return this;
}
public static Collector<Stock, ?, StockStatistics> collector() {
return Collector.of(StockStatistics::new, StockStatistics::accept, StockStatistics::combine);
}
public DoubleSummaryStatistics getProfitStat() {
return profitStat;
}
public DoubleSummaryStatistics getProfitPercentageStat() {
return profitPercentageStat;
}
}
This class serves as a wrapper around two DoubleSummaryStatistics. It delegates to them each time an element is accepted. In your case, since you're only interested in the sum, you could even use a Collectors.summingDouble instead of DoubleSummaryStatistics. Also, it returns the two statistics with getProfitStat and getProfitPercentageStat; alternatively, you could add a finisher operation that would return a double[] containing only both sums.
Then, you can use
StockStatistics stats = stocks.stream().collect(StockStatistics.collector());
System.out.println(stats.getProfitStat().getSum());
System.out.println(stats.getProfitPercentageStat().getSum());
A more generic way is to create a collector capable of pairing other collectors. You can use the pairing collector written in this answer and, also available in the StreamEx library.
double[] sums = stocks.stream().collect(MoreCollectors.pairing(
Collectors.summingDouble(Stock::getProfit),
Collectors.summingDouble(Stock::getProfitPercentage),
(sum1, sum2) -> new double[] { sum1, sum2 }
));
The sum of the profit will be in sums[0] and the sum of the profit percentage will be in sums[1]. In this snippet, only the sums are kept and not the whole stats.

Related

Averaging across multiple fields with IntSummaryStatistics

I'm trying to use Java 8 streams to create a single CarData object, which consists of an average of all the CarData fields in the list coming from getCars;
CarData = new CarData();
CarData.getBodyWeight returns Integer
CarData.getShellWeight returns Integer
List<CarData> carData = carResults.getCars();
IntSummaryStatistics averageBodyWeight = carData.stream()
.mapToInt((x) -> x.getBodyWeight())
.summaryStatistics();
averageBodyWeight.getAverage();
IntSummaryStatistics averageShellWeight = carData.stream()
.mapToInt((x) -> x.getShellWeight())
.summaryStatistics();
getShellWeight.getAverage();
I don't want to have to put each of these back together in my final returned result.
Visually, this is my list
getCars() : [
{CarData: { getBodyWeight=10, getShellWeight=3 } }
{CarData: { getBodyWeight=6, getShellWeight=5 } }
{CarData: { getBodyWeight=8, getShellWeight=19 } }
]
and the output I'm trying to achieve is a single object that has the average of each of the fields I specify. not sure If I need to use Collectors.averagingInt or some combo of IntSummaryStatistics to achieve this. Easy to do across one field for either of these techniques, just not sure what I'm missing when using multiple integer fields.
{CarData: { getBodyWeight=8, getShellWeight=9 } }
Starting with JDK 12, you can use the following solution:
CarData average = carData.stream().collect(Collectors.teeing(
Collectors.averagingInt(CarData::getBodyWeight),
Collectors.averagingInt(CarData::getShellWeight),
(avgBody, avgShell) -> new CarData(avgBody.intValue(), avgShell.intValue())));
For older Java versions, you can do either, add the teeing implementation of this answer to your code base and use it exactly as above or create a custom collector tailored to your task, as shown in Andreas’ answer.
Or consider that streaming twice over a List in memory is not necessarily worse than doing two operations in one stream, both, readability- and performance-wise.
Note that calling intValue() on Double objects has the same behavior as the (int) casts in Andreas’ answer. So in either case, you have to adjust the code if other rounding behavior is intended.
Or you consider using a different result object, capable of holding two floating point values for the averages.
You need to write your own Collector, something like this:
class CarDataAverage {
public static Collector<CarData, CarDataAverage, Optional<CarData>> get() {
return Collector.of(CarDataAverage::new, CarDataAverage::add,
CarDataAverage::combine,CarDataAverage::finish);
}
private long sumBodyWeight;
private long sumShellWeight;
private int count;
private void add(CarData carData) {
this.sumBodyWeight += carData.getBodyWeight();
this.sumShellWeight += carData.getShellWeight();
this.count++;
}
private CarDataAverage combine(CarDataAverage that) {
this.sumBodyWeight += that.sumBodyWeight;
this.sumShellWeight += that.sumShellWeight;
this.count += that.count;
return this;
}
private Optional<CarData> finish() {
if (this.count == 0)
return Optional.empty();
// adjust as needed if averages should be rounded
return Optional.of(new CarData((int) (this.sumBodyWeight / this.count),
(int) (this.sumShellWeight / this.count)));
}
}
You then use it like this:
List<CarData> list = ...
Optional<CarData> averageCarData = list.stream().collect(CarDataAverage.get());

How we I achieve add(4)(10)(20)(3)(1).total using Java Function?

I am learning usage of,
java.util.function.Function
I wrote a code which uses java Function to add 4 to itself,
the code is as follows,
public class Test01 {
public static void main(String[] args) {
Function<Integer,Integer> addFunction = new Function<Integer,Integer>() {
private int total = 0;
public Integer apply(Integer value) {
this.total += value;
return this.total;
}
};
int finalTotal = addFunction.andThen(addFunction)
.andThen(addFunction)
.andThen(addFunction)
.apply(4);
System.out.println(finalTotal);
}
}
When I run the above code the output which I get is
32
How can I achieve something which I did in javaScript which is as follows,
var fn19 = function(){
var addNum = function(num){
var fn = function(num2){
fn.sum += num2;
return fn;
};
fn.sum = num;
return fn;
};
print("addNum(3)(4)(3)(10) ==> "+addNum(3)(4)(3)(10).sum);
};
fn19();
The output of the above code is
addNum(3)(4)(3)(10) ==> 20
Can I have the same kind of java function call where I can pass as many number arguments and the addFunction will add those many numbers.
An example, as close as possible to your JavaScript code, would be
class QuestionableConstruct {
int sum;
QuestionableConstruct add(int num2) {
sum += num2;
return this;
}
}
Runnable fn19 = () -> {
IntFunction<QuestionableConstruct> addNum = num -> {
QuestionableConstruct fn = new QuestionableConstruct();
fn.sum = num;
return fn;
};
System.out.println("addNum(3)(4)(3)(10)==> "+addNum.apply(3).add(4).add(3).add(10).sum);
};
fn19.run();
A more Java like solution would be
interface Add {
int sum();
default Add add(int num) {
int sum = sum() + num;
return () -> sum;
}
static Add num(int num) {
return () -> num;
}
}
usable as
System.out.println("addNum(3)(4)(3)(10) ==> "+Add.num(3).add(4).add(3).add(10).sum());
Unlike the JavaScript construct, this uses real immutable functions. Consider
Add a = Add.num(1).add(2).add(3);
System.out.println("1+2+3+4+5 = "+a.add(4).add(5).sum());
System.out.println("1+2+3+10+20 = "+a.add(10).add(20).sum());
which works smoothly without interference.
But of course, if you just want to sum a variable number of items, use
System.out.println("addNum(3)(4)(3)(10) ==> "+IntStream.of(3, 4, 3, 10).sum());
or if you want a mutable accumulator, use
System.out.println("addNum(3)(4)(3)(10) ==> "+
IntStream.builder().add(3).add(4).add(3).add(10).build().sum());
which allows to keep the builder and pass it around.
You can't exactly do that in Java, what you are looking for is reducing a stream of values.
In other words: the "real" functional solution here isn't to call one method with multiple arguments. You rather have the values in some list, and then you define the function that "accumulates" over the content of that list, by applying a function on the elements.
See here for some examples.
The technique you're describing in the JavaScript world is taking advantage of a closure.
This is a nice side-effect of functions in JavaScript being first-class citizens. It's a way of associating functions with data in the enclosing scope and then being able to pass this association around without losing inner context. The most common/simple use of which is caching(its formal name being memoisation).
You would need functions(methods) in Java to be first class, but doing so would be redundant as classes by design are an entity which associates data and methods, making the whole concept of a closure in this context redundant.

Java 8 - how sum many fields into a dto?

Let's say I have a class Item like this:
class Item {
private long id;
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
Then I have a list with many itens, I want to know the sum of each of the values:
So, I know I could do something like
BigDecimal v1 = list.stream().map(Item::value1).reduce(BigDecimal.ZERO, BigDecimal::add);
However, this way I would need to do the same for each value, I'd like to know if there's some way of summing each attribute into only one Dto like:
class TotalItem {
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
TotalItem t = list.stream().map(???).reduce(BigDecimal.ZERO, BigDecimal::add);
Is this possible?
thanks in advance.
I didn't test it but I think that you can implement add function on Item like:
public Item add(Item other) {
Item newItem = new Item(this.value1 + other.value1,
this.value2 + other.value2,
this.value3 + other.value3);
return newItem;
}
and then do:
Item t = list.stream().reduce(BigDecimal.ZERO, Item::add);
How about the following way?
TotalItem t = new TotalItem();
list.stream().forEach(item -> {
t.value1+ = item.value1;
t.value2+ = item.value2;
t.value3+ = item.value3;
});
I'm making the assumption that Item/TotalItem are very large objects, which would make writing a toTotalItem and a summarise(TotalItem,TotalItem) by hand a large and laborious job. One that is completely boilerplate and easy to get wrong.
Change the data structure to be a list or map - This makes summarisation simpler, at the cost of readability of the code and type safety.
Use reflection to iterate over the fields.
TotalItem toTotalItem(Item item) {
Field[] targetFields = TotalItem.class.getFields();
Collection<Field> sourceFields = Item.class.getFields().stream()
.filter(x=>fieldNameIsIn(x, targetFields)
.collect(Collectors.toList());
TotalItem returnItem = new TotalItem();
for(Field field : sourceFields) {
toTargetField(field, targetFields).set(returnItem, (BigDecimal) field.get(item));
}
return returnItem;
}
boolean fieldNameIsIn(Field sourceField, Field[] targetFields) // exercise for the reader
Field toTargetField(Field sourceField, Field[] targetFields) // exercise for the reader
This code above is not neat, but should show the concept. The same concept could be used to summarise.
This reduces the amount of code you need to write, but at the cost of runtime speed. Reflection is also hard to get right and magic (which some developers do not like).
The faster option would be a custom annotation which adds in summarisation. However this would be large chunk of work. If you have a large number of objects that need this, then it may make sense. Like reflection it is hard to get right and magic (which some developers do not like). Luckily you do not need a build step as Javac supports annotation processing natively.
This answer is inspired by JDK way of doing similar operations. Namely, I'll be referencing DoubleSummaryStatistics class.
First, we define a holder for information about BigDecimals we'll be collecting:
public class BigDecimalSummaryStats {
private long count;
private MathContext mc;
private BigDecimal sum = BigDecimal.ZERO;
private BigDecimal max;
private BigDecimal min;
public BigDecimalSummaryStats(MathContext mathCtx) {
mc = requireNonNull(mathCtx);
}
public Supplier<BigDecimalSummaryStats> supplier(MathContext ctx) {
return () -> new BigDecimalSummaryStats(ctx);
}
public void accept(BigDecimal value) {
requireNonNull(value);
count++;
sum = sum.add(value, mc);
min = min.min(value);
max = max.max(value);
}
public void combine(BigDecimalSummaryStats other) {
requireNonNull(other);
count += other.count;
sum = sum.add(other.sum, mc);
min = min.min(other.min);
max = max.max(other.max);
}
public long getCount() {
return count;
}
public BigDecimal getSum() {
return sum;
}
public BigDecimal getMax() {
return max;
}
public BigDecimal getMin() {
return min;
}
public BigDecimal getAverage() {
long c = getCount();
return c == 0 ? BigDecimal.ZERO : getSum().divide(BigDecimal.valueOf(c), mc);
}
}
This will provide with nice general utility suitable for collecting summary from arbitrary sequences of BigDecimal values.
Then, we can define a Summary class for our Item:
public class ItemSummaryStats {
private BigDecimalSummaryStats value1;
private BigDecimalSummaryStats value2;
private BigDecimalSummaryStats value3;
// ... other fields as needed
public ItemSummaryStats(MathContext math) {
value1 = new BigDecimalSummaryStats(math);
value2 = new BigDecimalSummaryStats(math);
value3 = new BigDecimalSummaryStats(math);
}
public void accept(Item item) {
value1.accept(item.value1);
value2.accept(item.value2);
value3.accept(item.value3);
// ... other fields as needed
}
public void combine(ItemSummaryStats other) {
value1.combine(other.value1);
value2.combine(other.value2);
value3.combine(other.value3);
}
public TotalItem get(
Function<BigDecimalSummaryStats, BigDecimal> v1Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v2Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v3Mapper) {
TotalItem t = new TotalItem();
t.value1 = v1Mapper.get(value1);
t.value2 = v2Mapper.get(value2);
t.value3 = v3Mapper.get(value3);
return t;
}
public TotalItem getSum() {
return get(BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum);
}
public TotalItem getAverage() {
return get(BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage);
}
public TotalItem getMin() {
return get(BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin);
}
//.... other methods basically all the same. You get the idea.
}
And finally we use this goodness like this:
TotalItem totals = list.stream().collect(
Collector.of(() -> new ItemStatsSummary(MathContext.DECIMAL64),
ItemStatsSummary::accept,
ItemStatsSummary::combine,
ItemStatsSummary::getSum)
)
Cons of this approach:
Slightly longer development time than adhoc solutions.
Are far outweighed by the pros, or at least I'm convinced of it:
Follows separation of concerns principle: Item Stats are not actually concerned how to collect summary of specific field: they can trust that BigDecimalSummary works
Testable: Each part can be tested in its own suite. You can trust that every field will work the same since they use the same API.
Flexible: get(Function...) method exposes a big list of possibilities: you can collect sum of first field, an averabe of second and min of third if needed.

ArrayList<Object> how to differentiate objects added

the question is the same as in the title. i have arraylist to which i add incomes or expenses both in form of a object. will this loop sum up all elements, and is there a better way of doing this :?
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<Object> it = database.iterator(); it.hasNext();){
if (it.next() instanceof Expenses){
Expenses excalc = new Expenses();
excalc = (Expenses) it.next();
tmp -= excalc.value;
}
else {
incomes incalc =new incomes();
incalc = (incomes) it.next();
tmp += incalc.value;
}
}
System.out.format("the overall balance is %d",tmp);
}
Yes there are several better ways of doing it.
Firstly, I don't suggest you declare it as an Object list. Better is to declare an interface and then implement the interface in each of your classes:
interface BudgetValue {
double getValue();
}
class Expense implements BudgetValue {
public double getValue() {
return -value;
}
}
class Income implements BudgetValue {
public double getValue() {
return +value;
}
}
Then you can declare list of BudgetValues rather than Objects as the input to your method:
double sumBudgetValues(List<BudgetValues> budgetValues) {
}
There are two easy ways of summing them:
double total = 0.0;
for (BudgetValue value: budgetValues) {
total += value.getValue();
}
return total;
or using Java 8:
return budgetValues.stream()
.mapToDouble(BudgetValue::getValue)
.sum().orElse(0.0);
The streams method makes a lot more sense to me and allows it to be easily multithreaded if you have a lot of values to sum by turning it into a parallel stream.
There are some rare occassions where instanceof is justified but, as a rule of thumb, if you find yourself using it then start by asking yourself whether there's an interface missing.
I suggest making your Expenses and Incomes classes implement a common interface, for example LineItem. Now if you use signed values (positive for incomes and negatives for expenses), you only have to call getValue() on any implementation of LineItem and add it to your running total... no if/else needed, no collection of Object needed.
public void sumOfAllExpAndIn(){
int tmp = 0;
for (Iterator<LineItem> it = database.iterator(); it.hasNext();){
tmp += it.next().getValue();
}
}
System.out.format("the overall balance is %d",tmp);
}

How can I improve this block of code?

public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
Double discountAmount = 0.0;
switch (discountCode) {
case 'A':
discountAmount = 0.95 * itemTotal;
break;
case 'B':
discountAmount = 0.15 * itemTotal;
break;
}
return itemTotal - discountAmount;
}
Current implementation in order processor is closed for extension and open for modification for adding new discount codes, how can i improve the design to get rid of this limitation
In general, the presence of a switch is a pretty good giveaway as to what should be a class instead. So, a first stab at it would be something like this:
public interface Discounter {
public double applyDiscount(double itemTotal);
}
public class OrderProcessor {
private Map<Char, Discounter> discounts = new HashMap<Char, Discounter>();
public void addDiscounter(Char discountCode, Discounter discounter) {
discounts.put(discountCode, discounter);
}
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
double itemTotal = order.getItemTotal();
double discountAmount = 0.0;
if (discounts.hasKey(discountCode))
discountAmount = discounter.applyDiscount(itemTotal);
return itemTotal - discountAmount;
}
}
This would then be extended through something like this:
processor.addDiscounter('A', new Discounter() {
public double applyDiscount(double itemTotal) {
return 0.95 * itemTotal;
}
});
You could make a remove method as well, and then your discounters can become more complex, consulting external data, etc. You may want to open up the interface a bit and pass in the whole order for more examination.
Note: If this is something you're going to be doing in production I have two pieces of unsolicited advice:
Consider using something like JBoss Drools to handle your business logic instead of this; it's a lot more powerful and flexible.
Please don't use double for actual financial calculations. :)
As you have pointed out that the discount code needs to be changeable, it is best to separate out the actual discount codes from the code. Maintain the discount codes in an xml or settings file and lazy load the values into a dictionary/hashset before using them.
For example your xml could look like this,
<Discounts>
<Discount code="A" value="0.05"/>
<Discount code="B" value="0.10"/>
<Discount code="C" value="0.15"/>
</Discounts>
In your calculateTotalPriceWithDiscountCode, populate a dictionary with the values read from this xml.
if(discountsDictionary == null)
{
discountsDictionary = LoadValuesFromXml(xmlFilePath);
}
In case your discounts xml is likely to change during program execution then perform the Load operation when you want the discount value (as compared to loading once in the above code fragment).
Then access the code (key) to retrieve the discount (value),
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}
Pull the logic for calculating totals based on an order into its own class/interface:
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
In a real system, I'd make the TotalCalculator an interface, which would have the additional advantage of being able to calculate order totals in other ways than just a percentage discount reduction.
This solution is also very flexible in allowing you to create your TotalCalculators (or implementations if an interface) using other mechanisms than manually coding them into a factory. You can use an IoC container to create and inject them or use a ServiceLoader to find and load them, for example.
My idea is maintain discounts separately.
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
return itemTotal - (itemTotal* Discounts.GetDiscounts(discountCode));
}
}
////////////////
class Discounts
{
public static double GetDiscounts(char discountCode)
{
switch (discountCode) {
case 'A':
return 0.95d;
case 'B':
return 0.15d;
default:
return 0.00d;
}
}
}
In this calculateTotalPriceWithDiscountCode function, it is not a good idea to pass a discount code as parameter. Well, 3rd person , who review your code , would not understand would not understand what does it mean except you, a kind of code smell.
One of a suggestion is that you need to create another class called Discount, and you pass the Discount object as a parameter, and you get the internal value from its public method.
i.e.
public class Discount {
//Use a hash map to store your Code associate with your discountAmount
public Discount(char discountCode){
this.discountCode = discountCode
}
public int getDiscountAmount(){
....
....
}
}
Right now, what you actually need to modify will be the Discount Class only, and your calculateTotalPriceWithDiscountCode will not need to care.
You could use a separate xml file for storing codes as well as their calculation mechanishms.
This will remove the limitation of inablility to add new discount code.
XML File: discounts.xml
<discount-codes>
<discount-code>
<code>A</code>
<val>0.15</val>
</discount-code>
<discount-code>
<code>B</code>
<val>0.95</val>
</discount-code>
</discount-codes>
Note: Operation code (What am I intended to do with the values?) is not currently implemented. You can implement the same at your end.
Use an XML parser class:
Class: DiscountModel.java (This class is the model to store the discount codes)
public class DiscountModel {
char code;
Double val;
// Implement getters and setters
}
Class: DiscountParser.java (This will parse the discounts.xml file and store the codes in a list)
public class DiscountParser {
List<DiscountModel> discountsList;
// Getters and Setters for discountsList
// Parser Code
public void parseDiscounts() {
// Code here
}
// Add new discount
public void addDiscount() {
// Code
}
// Remove discount
public void removeDiscount () {
// Code
}
}
Class: OrderProcessor.java (This will bring out the discounted value after calculation)
/**
* Call this class when calculations need to be done.
*/
public class OrderProcessor {
// Declare instance of DocumentParser
DocumentParser dc1;
// Getter and setter for dc1
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
// Find the corresponding discountcode and
// value from the list of values in the
// Class DocumentParser
// Use the corresponding values to calculate
// the discount and return the value
}
}
Whenever a new code is to be added, you can insert the same to the xml file. The same applies if the discount code needs to be removed.
Hope the above helps.

Categories

Resources