java - 使用 Java 8 Streams 完成删除循环
问题描述
我有一个需要根据特定标准映射的文档对象列表。有一个实用程序函数可以接受任何 2 种文档类型,并确定它们是否符合许多标准,例如文档类型、它们是否共享任何作者等。代码有效,但我想使用 Java Streams 来解决它如果可能的话。
我目前使用以下代码解决了这个问题:
class Document{
private String genre;
private List<Author> authors;
private String isbn;
private boolean paperBack;
...
}
我还使用了一个库实用程序,该实用程序具有在给定一系列匹配条件和一对文档的情况下返回 true 的函数。它只是返回一个布尔值。
boolean matchesOnCriteria(Document doc1, Document doc2, Criteria criteria){
...
}
这是用于查找与提供的条件匹配的书籍的匹配代码
DocumentUtils utils = DocumentUitls.instance();
Criteria userCriteria = ...
List<Pair> matches = new ArrayList<>();
List<Document> documents = entityManager.findBy(.....);
for(Document doc1 : documents){
for(Documents doc2 : documents){
if(!doc1.equals(doc2){
if (utils.matchesOnCriteria(doc1,doc2, userCriteria)) {
Pair<Document> p = new Pair(doc1,doc2);
if(!matches.contains(p)){
matches.add(p);
}
}
}
}
}
}
如何使用 Streams 做到这一点?
解决方案
使用以下解决方案的想法Steam::reduce
很简单:
将合格的文档对分组为
Map<Document, List<Document>>
具有所有可能的可接受组合。假设奇数和偶数文档是成对的:D1=[D3, D5], D2=[D4], D3=[D1, D5], D4=[D2], D5[D1, D3] // dont mind the duplicates
使用
Stream::reduce
您可以实现以下步骤:将条目转换为
Pair<>
,D1-D3, D1-D5, D2-D4, D3-D1, D1-D5, D4-D2, D5-D1, D5-D3
保存这些项目以
Set
保证相等的对出现一次 (D1-D3
=D3-D1
)。条件 thePair
must override bothObject::equals
and andObject:hashCode
and 实现基于存在的两个文档的相等性。D1-D3, D1-D5, D3-D5, D2-D4
将特定集合减少(合并)为单个集合
Set<Pair<Document>>
。
Map<Document, List<Document>> map = documents.stream()
.collect(Collectors.toMap( // Collected to Map<Document, List<Document>>
Function.identity(), // Document is the key
d1 -> documents.stream() // Value are the qualified documents
.filter(d2 -> !d1.equals(d2) &&
utils.matchesOnCriteria(d1,d2, userCriteria)
.collect(Collectors.toList()))); // ... as List<Document>
Set<Pair<Document>> matches = map.entrySet().stream().reduce( // Reduce the Entry<Dokument, List<Document>>
new HashSet<>(), // ... to Set<Pair<>>
(set, e) -> {
set.addAll(e.getValue().stream() // ... where is
.map(v -> new Pair<Document>(e.getKey(), v)) // ... the Pair of qualified documents
.collect(Collectors.toSet()));
return set;
},
(left, right) -> { left.addAll(right); return left; }); // Merge operation
条件!matches.contains(p)
是多余的,有更好的方法来确保不同的值。使用Stream::distinct
或收集Set
作为无序独特集合的流。
在Baeldung's阅读更多内容:删除所有重复项。
推荐阅读
- sql - Google BigQuery 联合查询连接错误
- java - Flyway Mutli Schema:如何在迁移脚本sql文件中指定模式名称
- python - 我在 python Beautiful Soup 中得到一个空列表
- highcharts - 如果 x 轴值太小,则内部的 X 范围图表标签不可见
- date - NestJS gRpc:为什么 Nestjs 将日期字符串转换为不同的格式?
- c# - 如何从 SQLite 中选择带小数秒的时间并在 C# 中插入到 SQL Server
- flutter - 指示器选项卡颤动
- javascript - 无法在 vue js 生产中播放视频(Vue Cli 3)
- javascript - 拆分数组并将值加在一起或根据jquery中的多项选择进行减法
- dart - 如何在 Dart 中测试两个持续时间是否大致相等