java - 如何使用流口水对列表中的元素进行分组
问题描述
我是 Drools 的新手,我正在努力寻找以下问题的解决方案:
我有一个 Account 类的列表:
class Account {
private String name;
private float amount;
}
我想在 drools 中使用名称对帐户列表进行分组。例如:
Account a = new Account("Science", 100);
Account b = new Account("Science", 200);
List<Account> list = new ArrayList<String>();
list.add(a);
list.add(b);
现在我需要一个流口水规则,它应该使用名称对列表中的元素进行分组,并提供具有“科学,300”的列表。
请建议。
解决方案
正如 Ironluca 在评论中指出的那样,您使用了错误的工具来完成这项工作。正确的解决方案是使用 Java 流;即使是一个简单的 for 循环也可以解决您的问题。
当然,由于您可以在螺丝上使用锤子,因此您可以使用 Drools 来做到这一点。我将包含一个示例规则和一个解释,尽管它比基于流的解决方案(甚至是 for 循环)效率低得多。
我将假设这个模型具有适当的 getter、setter 和全参数构造函数:
class Account {
String name;
int quantity;
}
然后,此规则将使用“分组”帐户填充“输出”列表。我已将此“输出”列表声明为全局列表,这不是最佳实践,但无论如何都不建议这样做,因为它不是适合这项工作的工具。
global List $output;
rule "Consolidate duplicates"
when
$inputs: List()
Account( $name: name ) from $inputs
$duplicates: List()
from collect( Account( name == $name ) from $inputs )
$total: Number()
from accumulate( Account( $value: quantity ) from $duplicates, sum( $value ) )
then
$output.add(new Account($name, $total));
end
规则的第一部分标识输入列表中共享相同名称的 Account 实例的子集。我使用collect
它是因为这是原始输入的一个简单子集。下一步是用来accumulate
总结这些重复项的数量。然后我们在规则的 RHS 上的输出列表中添加一个新实例,其中包含合并数量和共享名称。请注意,对于具有唯一名称的帐户,该规则同样适用;的长度没有限制$duplicates
,累积只是一个确定的数量。
$inputs
就地修改也是可行的,但很棘手,因为您必须担心并发修改异常。更清洁的实现是使用
当然,这比它必须要复杂得多。Java 8 流提供了一个groupingBy
收集器,它允许您通过对象内的属性轻松创建映射:
Map<String, List<Account>> accountsByName = accounts.stream()
.collect(groupingBy(Account::getName));
然后,您可以通过迭代值集轻松地转换它。
这个另一个问题详细介绍了其他“流中重复项的总和”场景:Java 8 stream sum entries for duplicate keys
推荐阅读
- ansible - 角色内的 Ansible 自定义模块
- typescript - 转译的打字稿意外添加了“默认”导出对象
- node.js - 错误 - expressSessionMiddleware 不是函数
- java - 为什么在 Android 中使用 Azure 面部 API 的 URL 调用会出现 FileNotFoundException?
- excel - 为什么更改数据透视表范围行上出现无效过程或调用错误?
- android - 添加新的 Maven 和依赖项后,Studio 下载的文件会发生什么情况?
- css - 如何删除进度条Bootstrap 4中的边距区域?
- r - R:以编程方式分小部分读取非常大的数据
- angular - Highchart/Chart.js/FusionChart:列范围自定义图表
- drools - 更改 freemarker 模板中的“#”键