【问题标题】:Java 8 lambdas nested MapJava 8 lambdas 嵌套映射
【发布时间】:2015-06-13 20:24:53
【问题描述】:

我正在尝试使用 Java-8 lambdas 来解决以下问题:

给定一个List<Transaction>,对于每个Category.minorCategory,我需要每个Category.minorCategoryTransaction.amount 和一个Transaction.accountNumberMap 的总和以及每个Transaction.accountNumberTransaction.amount 的总和。根据下面的代码,我有这个工作。 我现在需要按Category.majorCategory 分组,基本上返回Map<String, Map<String, MinorCategorySummary>> 键入Category.majorCategory

Category.majorCategory 分组阶段之前,我已经完成了所有工作,但很难找到解决方案;使用 lambda 进行编程的范式转变证明了一条陡峭的学习曲线。

TransactionBreakdown 是动作发生的地方,我想返回Map<String, Map<String, MinorCategorySummary>>

public class Transaction {

    private final String accountNumber;
    private final BigDecimal amount;
    private final Category category;

}

public class Category {

    private final String majorCategory;
    private final String minorCategory;

}

public class MinorCategorySummary {

    private final BigDecimal sumOfAmountPerMinorCategory;
    private final Map<String, BigDecimal> accountNumberSumOfAmountMap;
    private final Category category;

}

public class TransactionBreakdown {

    Function<Entry<String, List<Transaction>>, MinorCategorySummary> transactionSummariser = new TransactionSummariser();

    public Map<Object, MinorCategorySummary> getTransactionSummaries(List<Transaction> transactions) {
        return transactions
                .stream()
                .collect(groupingBy(t -> t.getCategory().getMinorCategory()))
                .entrySet()
                .stream()
                .collect(
                        toMap(Entry::getKey,
                                transactionSummariser));
    }

}

public class TransactionSummariser implements Function<Entry<String, List<Transaction>>, MinorCategorySummary> {

    @Override
    public MinorCategorySummary apply(
            Entry<String, List<Transaction>> entry) {
         return new MinorCategorySummary(
                    entry.getValue()
                            .stream()
                            .map(Transaction::getAmount)
                            .collect(reducing(BigDecimal.ZERO, BigDecimal::add)),
                    entry.getValue()
                            .stream()
                            .collect(
                                    groupingBy(Transaction::getAccountNumber,
                                            mapping(Transaction::getAmount,
                                                    reducing(BigDecimal.ZERO, BigDecimal::add)))), 
                                                    entry.getValue().get(0).getCategory());
    }

}

【问题讨论】:

    标签: java lambda java-8 java-stream collectors


    【解决方案1】:

    我觉得你的班级设计很奇怪。为什么只将类别放入摘要类中,然后将类别作为映射键?有一个没有类别的摘要类会更有意义:

    public class TransactionSummary {
    
        private final BigDecimal amount;
        private final Map<String, BigDecimal> acctToTotal;
    
        TransactionSummary(Map<String, BigDecimal> acctToTotal) {
            this.acctToTotal = Collections.unmodifiableMap(acctToTotal);
            this.amount = acctToTotal.values().stream()
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
    
        public static Collector<Transaction, ?, TransactionSummary> collector() {
            // this can be a static constant
            return collectingAndThen(
                toMap(Transaction::getAccountNumber,Transaction::getAmount,BigDecimal::add),
                TransactionSummary::new
            );
        }
    
        // getters
    }
    

    现在你的两个问题都解决了,没有多余的:

    Map<String, TransactionSummary> minorSummary = transactions.stream()
            .collect(groupingBy(
                    t -> t.getCategory().getMinorCategory(),
                    TransactionSummary.collector()
            ));
    
    Map<String, Map<String, TransactionSummary>> majorMinorSummary = transactions.stream()
            .collect(groupingBy(
                    t -> t.getCategory().getMajorCategory(),
                    groupingBy(
                            t -> t.getCategory().getMinorCategory(),
                            TransactionSummary.collector()
                    )
            ));
    

    【讨论】:

    • 感谢您的解决方案,当您看到它时它看起来很简单,但我很难到达那里。关于类别,你是对的,它不应该出现在摘要中 - 经过几个小时试图让我了解 lambdas 后,它才出现在那里 - 我变得绝望了 :)
    猜你喜欢
    • 1970-01-01
    • 2016-02-12
    • 2019-01-19
    • 2016-09-24
    • 2019-05-16
    • 2016-12-12
    • 2014-11-23
    • 2020-03-19
    • 2018-10-23
    相关资源
    最近更新 更多