Given the following class and data structure below, I want to calculate the sum of count for each consecutive 3 element similar to following results:
public class SaleTxn {
private int id;
private String txnDate;
private int amount;
}
Data as below
id txnDate amount
1 2018-10-10 100
2 2018-10-11 200
3 2018-10-12 100
4 2018-10-13 100
5 2018-10-14 200
6 2018-10-15 200
... ...
And the window size is 3, means just sum of the past 3 element, and the expected result like below
2018-10-10 ~ 2018-10-12 Total: 100+200+100 = 400
2018-10-13 ~ 2018-10-14 Total: 100+200+200 = 500
...
I have a List code below:
List<SaleTxn> myList; //
myList.stream().filter(x -> ??????)
.mapToInt(SouthboundShareholding::getAmount)
.sum();
How can I implement?
I think the core problem is partition list,if you can use Google Guava this will be very simple like the bellow code:
Code:
List<SaleTxn> saleTxns = new ArrayList<>();
saleTxns.add(new SaleTxn(1, "2018-10-10", 100));
saleTxns.add(new SaleTxn(2, "2018-10-11", 200));
saleTxns.add(new SaleTxn(3, "2018-10-12", 100));
saleTxns.add(new SaleTxn(4, "2018-10-13", 100));
saleTxns.add(new SaleTxn(5, "2018-10-14", 200));
saleTxns.add(new SaleTxn(6, "2018-10-15", 200));
// implement of filter
saleTxns = saleTxns.stream().filter(saleTxn -> true).collect(Collectors.toList());
// partition the list and sum all value
List<Integer> result = Lists.partition(saleTxns, 3).stream()
.mapToInt(value -> value.stream().mapToInt(SaleTxn::getAmount).sum())
.boxed()
.collect(Collectors.toList());
System.out.println(result);
The output of code:
[400, 500]
You can achieve this with only myList.size()/3
iterations. Use an IntStream
to iterate with custom increments (we use 3 which is the window size):
IntStream.iterate(0, n -> n + 3).limit(myList.size() / 3)
Then collect the entries in a map:
Collectors.toMap(i -> myList.subList(i, i + 3), i -> (myList.get(i).getAmount()
+ myList.get(i + 1).getAmount() + myList.get(i + 2).getAmount()))
Let's assume I've added an extra item to myList
:
myList.add(new SaleTxn(7, "2018-10-16", 300));
Now myList.size()
equals to 7 and the solution only works if the size is 3, 6, or 9,... (myList.size() % 3 == 0
)
To cover the items left we need to check if there is items remaining:
if (myList.size() % 3 != 0) {
List<SaleTxn> remainderList = new ArrayList<>();
int remainderSum = 0;
for (int j = myList.size() % 3; j > 0; j--) {
remainderSum += myList.get(myList.size() - j).getAmount();
remainderList.add(myList.get(myList.size() - j));
}
result.put(remainderList, remainderSum);
}
Full code:
Map<List<SaleTxn>, Integer> result = IntStream.iterate(0, n -> n + 3).limit(myList.size() / 3).boxed()
.collect(Collectors.toMap(i -> myList.subList(i, i + 3), i -> (myList.get(i).getAmount()
+ myList.get(i + 1).getAmount() + myList.get(i + 2).getAmount())));
if (myList.size() % 3 != 0) {
List<SaleTxn> remainderList = new ArrayList<>();
int remainderSum = 0;
for (int j = myList.size() % 3; j > 0; j--) {
remainderSum += myList.get(myList.size() - j).getAmount();
remainderList.add(myList.get(myList.size() - j));
}
result.put(remainderList, remainderSum);
}
result.entrySet().forEach(e -> System.out.println(e));
Output:
[SaleTxn [id=4, txnDate=2018-10-13, amount=100], SaleTxn [id=5, txnDate=2018-10-14, amount=200], SaleTxn [id=6, txnDate=2018-10-15, amount=200]]=500
[SaleTxn [id=1, txnDate=2018-10-10, amount=100], SaleTxn [id=2, txnDate=2018-10-11, amount=200], SaleTxn [id=3, txnDate=2018-10-12, amount=100]]=400
[SaleTxn [id=7, txnDate=2018-10-16, amount=300]]=300
I added a toString()
method to SaleTxn
class to get the output above:
@Override
public String toString() {
return "SaleTxn [id=" + id + ", txnDate=" + txnDate + ", amount=" + amount + "]";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With