简体   繁体   中英

How to sum object by time period on a Map object by stream in Java8?

I have a Map object. The key is ID, value is a list of Transaction . Below is the Transaction class code:

public class Transaction {
    private double amount;
    private LocalDateTime timestamp;
...
}

Map transactions = new HashMap<String, List<Transaction>>();

// how to stream transactions here?

I am trying to get the sum amount of transactions happen within 24 hours for each key . First, I need to loop transaction List for each key. Then group by the transaction based on timestamp. Then sum the value for each grouped transaction.

For example, the map object has below value:

'012345': [ {'05-05-2019:10.00.00', 100}, {'05-05-2019:11.00.00', 100},{'05-05-2019:12.00.00', 100} ]
`678900`: [ {'05-06-2019:10.00.00', 100}, {'05-06-2019:11.00.00', 100},{'05-07-2019:10.30.00', 100} ]

It has two keys 012345 and 678900 , and each key has three transactions. The transactions under the key 012345 happens within 24 hours while the transactions under 678900 happens across 2 days. The output should be the sum of amount for 24 hours window period. So it looks like:

'012345': [300],
'678900': [200, 200]

The three transactions under 678900 has two 24 hours window period. So it gives two 200 amount. The middle transaction get calculated twice since it is covered by two 24 hours window period.

Below is my thinking:

transactions.values().forEach(txnList -> {
            Map<Integer, DoubleSummaryStatistics> collect = txnList.stream().collect(Collectors.groupingBy(txn -> txn.getTimestamp().getHour() / 24, Collectors.summarizingDouble(Transaction::getAmount)));
        });

but it doesn't return the right value. I don't know how I should proceed this logic. Can anyone point me the right way to do that?

If you are open to use a third party library, there are some APIs available in Eclipse-Collections , which will do your job pretty neatly. This works with any Java java.lang.Iterable . The code would look like follows:

    Map<String, List<Transaction>> transactionsMap = getMapOfTransactionalData(...);
    final long currentTime = Instant.now().getEpochSecond();
    Map<String, Double> idTransactionSumMap = MapIterate.collect(transactionsMap, (id, transList) -> {
        Collection<Transaction> transactionsForTimeRange = Iterate.select(transList, transaction -> {
            // Implement your condition to compare time, below is just an example, you can define your range as well
            long transactionTime = transaction.getTimestamp().toEpochSecond(ZoneOffset.UTC);
            return transactionTime > currentTime - TimeUnit.HOURS.toMillis(24);
        });
        return Tuples.pair(id, Iterate.sumOfDouble(transactionsForTimeRange, Transaction::getAmount));
    });

If you use MutableMap and MutableList from eclipse-collection, code will be like:

MutableMap<String, MutableList<Transaction>> transactionsMap = getMapOfTransactionalData(...);
long currentTime = Instant.now().getEpochSecond();
MutableMap<String, Double> idTransactionSumMap = transactionsMap.collect((id, transList) -> Tuples.pair(id, transList.select(transaction -> {
    // your condition to compare time
    long transactionTime = transaction.getTimestamp().toEpochSecond(ZoneOffset.UTC);
    return transactionTime > currentTime - TimeUnit.HOURS.toMillis(24);
}).sumOfDouble(Transaction::getAmount)));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM