使用Java8流完成循环删除
我有一个文档对象列表,需要根据某些条件进行映射。有一个实用函数,它接受任意两种文档类型,并确定它们是否符合许多标准,如文档的类型、它们是否共享任何作者等。代码可以工作,但I’;如果可能的话,我想用Java Streams来解决这个问题 我目前通过使用以下代码解决此问题:使用Java8流完成循环删除,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我有一个文档对象列表,需要根据某些条件进行映射。有一个实用函数,它接受任意两种文档类型,并确定它们是否符合许多标准,如文档的类型、它们是否共享任何作者等。代码可以工作,但I’;如果可能的话,我想用Java Streams来解决这个问题 我目前通过使用以下代码解决此问题: class Document{ private String genre; private List<Author> authors; private String isbn;
class Document{
private String genre;
private List<Author> authors;
private String isbn;
private boolean paperBack;
...
}
以下是匹配代码,用于查找符合所提供条件的书籍
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);
}
}
}
}
}
}
DocumentUtils-utils=DocumentUitls.instance();
条件userCriteria=。。。
列表匹配项=新的ArrayList();
List documents=entityManager.findBy(…);
用于(文件doc1:文件){
用于(文档doc2:文档){
如果(!doc1.等于(doc2){
if(utils.matchesconcriteria(doc1、doc2、userCriteria)){
对p=新对(doc1,doc2);
如果(!matches.contains(p)){
添加(p);
}
}
}
}
}
}
如何使用Streams实现这一点?使用以下解决方案的想法很简单:
Map
。假设奇偶文档成对:
D1=[D3, D5], D2=[D4], D3=[D1, D5], D4=[D2], D5[D1, D3] // dont mind the duplicates
Stream::reduce
可以实现以下步骤:
- 将条目转换为
对
- 将这些项保存到
以保证相等的对出现一次(Set
=D1-D3
)。条件D3-D1
对必须覆盖
和对象::equals
,并基于存在的两个文档实现相等对象:hashCode
D1-D3, D1-D5, D3-D5, D2-D4
- 将特定集合减少(合并)为单个集合
Set
Map Map=documents.stream()
.collect(Collectors.toMap(//收集到映射
Function.identity(),//文档是键
d1->documents.stream()//值为符合条件的文档
.过滤器(d2->!d1.等于(d2)和
utils.matchesconcriteria(d1、d2、用户标准)
.collect(Collectors.toList());/…作为列表
Set matches=map.entrySet().stream().reduce(//减少条目
要设置的新HashSet(),/
(集合,e)->{
set.addAll(e.getValue().stream()/…其中是
.map(v->new Pair(e.getKey(),v))/…这对符合条件的文档
.collect(Collectors.toSet());
返回集;
},
(左,右)->{left.addAll(右);return left;});//合并操作
条件!matches.contains(p)
是冗余的,有更好的方法来确保不同的值。使用或收集流以设置
,这是一个无序的不同集合
阅读更多信息。除非你有充分的理由这样做,否则我不会为了一行难读的代码而牺牲简洁性和简单性。你的代码对我来说非常简单。或者这只是为了宽容?顺便说一句:你在两个循环上重复相同的列表。这是故意的吗?他在比较一个数据和其他数据,所以是这样的可能是有意的,这里有一个很大的性能问题。您可以检查类似于B的a和类似于a的B。是的,您跳过了a=a,但是。这应该通过索引
i
->0..size-1和j
->.size来完成。您可以使用.intStream并映射到对象,但是对于streams有更好的候选者。是的,因为有一个d列表中的不同文件。非常感谢!非常感谢!
D1-D3, D1-D5, D2-D4, D3-D1, D1-D5, D4-D2, D5-D1, D5-D3
D1-D3, D1-D5, D3-D5, D2-D4
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