Есть ли функциональный способ обхода потока, накапливающего и фильтрующего на основе последних обработанных элементов? - PullRequest
0 голосов
/ 08 мая 2019

Я получил заказанный список запросов транзакций, сделанных за период всеми клиентами, которые имеют тот же кредитный лимит. Моя цель - создать список всех транзакций, которые были выполнены после того, как кредитный лимит был пройден.

Для этого мне нужно взять сумму каждой транзакции и снять кредитный лимит клиента.

Я учусь и пытаюсь решить эту проблему с помощью потоков java11, но я не смог найти способ сделать это одним и тем же способом.

Изначально я сгруппировал транзакции по клиенту:

Map<Customer, List<Transaction>> result = transactions.stream()
       .collect(Collectors.groupingBy(Transaction::getCustomer));

Но затем я просмотрел результат, накапливая суммы транзакций и добавляя транзакцию в требуемый список, когда ее сумма превышает лимит:

List<String> toAnalise = new ArrayList<>();
result.entrySet().forEach(entry -> {
    int total = 0;
    for (Transaction transaction : entry.getValue()) {
      if ((total + transaction.amount) <= creditLimit ){
            total += transaction.amount;
        } else {
          toAnalise.add(transaction.transactionId);
        }               
    }
});

У меня такое ощущение, что это можно улучшить :)


Я улучшил свое решение ... кажется лучше :)

Теперь я возвращаю список транзакций напрямую:

List<String> toBeAnalised = transactions.stream()
        .map(t -> new Transaction(t, creditLimit))
        .collect(groupingBy(Transaction::getConsumer,
                collectingAndThen(toCollection(TreeSet::new),
                TransactionsVersion2::validateTransactions)))
        .values().stream().flatMap(List<String>::stream)
        .collect(toList());

Также я перенес проверку транзакции на собственный метод, позволяющий вызывать ее из потоковой обработки:

private static List<String> validateTransactions(Set<Transaction> transactions) {
    int total = 0;
    List<String> rejected = new ArrayList<>();
    for (Transaction transaction : transactions) {
        if ((total + transaction.amount) <= transaction.consumer.limit)
        {
            total += transaction.amount;
        } else {
            rejected.add(transaction.transactionId);
        }
    }
    return rejected;
}

Можно ли его еще улучшить?

1 Ответ

1 голос
/ 08 мая 2019

с использованием takeWhile что-то вроде:

List<String> toAnalise = new ArrayList<>();
for (List<Transaction> value : result.values()) {
    AtomicInteger total = new AtomicInteger(0);
    toAnalise.addAll(value.stream()
            .takeWhile(a -> total.addAndGet(a.amount) <= creditLimit)
            .map(t -> t.transactionId).collect(Collectors.toList()));
}
...