【问题标题】:Java 8: groupingBy with associated object's property? [Cyclic Inference]Java 8:groupingBy 与关联对象的属性? 【循环推理】
【发布时间】:2014-11-29 00:39:02
【问题描述】:

这就是我的Test 的样子:

@Test
    public void testFunctional() 
    {
        final Member member = new Member("email", "memberExternalId", "clientId", "clientSecret");
        final Category foodCategory = new Category("Groceries", "Food");
        final Category utilityCategory = new Category("Internet", "utility");

        final List<Transaction> transactions = new ArrayList<>();
        {
            transactions.add(new Transaction("food1", new BigDecimal("10.00"), true, LocalDateTime.now(), member, foodCategory));
            transactions.add(new Transaction("food2", new BigDecimal("20.00"), true, LocalDateTime.now(), member, foodCategory));
        }
        {
            transactions.add(new Transaction("utility1", new BigDecimal("100.00"), true, LocalDateTime.now(), member, utilityCategory));
            transactions.add(new Transaction("utility2", new BigDecimal("200.00"), true, LocalDateTime.now(), member, utilityCategory));
        }

        final Map<String, List<BigDecimal>> groupByCategory = transactions.stream().collect(Collectors.groupingBy(Category::getGroupName));
    }

Category 看起来像这样:

public class Category 
{
    @Id
    private String id;

    @Column(nullable = false)
    private String name;

    @Column(name = "group_name", nullable = false)
    private String groupName;

    @Column(name = "created_at")
    private LocalDateTime createdAt;
...
}

当我这样做时:

final Map<String, List<BigDecimal>> groupByCategory = transactions.stream().collect(Collectors.groupingBy(Category::getGroupName));

IntelliJ 向 Cyclic Inference 投诉

我是第一次尝试这个Java 8 功能,但不确定是什么原因造成的。

【问题讨论】:

  • 您的transactions 列表包含Transaction 值。您希望在哪里应用Category::getGroupName
  • 不确定你的意思,但每个Transaction 都有Category,其中有groupName,我想根据他们的groupName 对事务进行分组。这有意义吗?
  • 所以您希望Transactions 按其Category 的名称分组?
  • groupNameCategory 分组。如果你在上面的代码中看到CategorygroupName
  • IDE 可能会报告误导性错误消息。您需要问自己的第一件事是:“Java 如何使用Category::getGroupName 给定Transaction 类型的值(由stream() 提供)?”

标签: java intellij-idea java-8


【解决方案1】:

您的输入是List&lt;Transaction&gt;,您可以从中创建Stream&lt;Transaction&gt;。 当您将此Stream 收集到Map 中时,您应该提供一个收集器,它将每个Transaction 映射到应该分组的键。

您希望通过GroupNameCategoryTransactionTransactions 进行分组。由于Category::getGroupName 不是Transaction 的方法,所以这里不能使用方法引用。相反,您可以使用 lambda 表达式:

final Map<String, List<Transaction>> groupByCategory = 
    transactions.stream()
                .collect(Collectors.groupingBy(t -> t.getCategory().getGroupName()));

另请注意,此分组将产生Map&lt;String, List&lt;Transaction&gt;&gt;,而不是Map&lt;String, List&lt;BigDecimal&gt;&gt;

【讨论】:

  • 谢谢,我会试试这个。所以如果我想在Transaction 中添加金额,我应该在上面创建的Map 上应用Map-Reduce,对吧?
  • @daydreamer “在交易中添加金额”是什么意思?
  • 我的地图中的BigDecimal 是用于将Transaction 中的所有amountgroupName 分组时添加。这有意义吗?
【解决方案2】:

如果您想获得按类别分组的金额,则可以将groupingBy 收集器与mapping 收集器结合使用:

    Map<String, List<BigDecimal>> amountsByCategory = transactions.stream()
            .collect(Collectors.groupingBy(t -> t.getCategory().getGroupName(),
                     Collectors.mapping(Transaction::getAmount, 
                     Collectors.toList())));

也可以使用Collectors.reducing 获得每组的总金额:

    Map<String, BigDecimal> totalAmountByCategory = transactions.stream()
            .collect(Collectors.groupingBy(t -> t.getCategory().getGroupName(),
                     Collectors.mapping(Transaction::getAmount, 
                     Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

【讨论】:

  • 我认为第一部分非常有用:这是一种常见情况:在对象集合中,通常您有一个属性作为分组依据(组名)的键,另一个作为感兴趣的值(数量)放入清单。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-10-03
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多