简体   繁体   English

如何在Java8中按流在Map对象上按时间段对对象求和?

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

I have a Map object. 我有一个Map对象。 The key is ID, value is a list of Transaction . key是ID,值是Transaction列表。 Below is the Transaction class code: 以下是Transaction类代码:

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 . 我试图让每个key在24小时内完成交易总额。 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. 它有两个键012345678900 ,每个键有三个事务。 The transactions under the key 012345 happens within 24 hours while the transactions under 678900 happens across 2 days. 密钥012345下的交易发生在24小时内,而678900下的交易发生在2天内。 The output should be the sum of amount for 24 hours window period. 输出应为24小时窗口期间的总和。 So it looks like: 所以它看起来像:

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

The three transactions under 678900 has two 24 hours window period. 678900下的三笔交易有两个24小时的窗口期。 So it gives two 200 amount. 所以它给了两个200金额。 The middle transaction get calculated twice since it is covered by two 24 hours window period. 中间交易计算两次,因为它被两个24小时的窗口期覆盖。

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. 如果您愿意使用第三方库,那么Eclipse-Collections中提供了一些API,它们可以很好地完成您的工作。 This works with any Java java.lang.Iterable . 这适用于任何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: 如果你使用eclipse-collection中的MutableMap和MutableList,代码就像:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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