使用Java8流完成循环删除

使用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;

我有一个文档对象列表,需要根据某些条件进行映射。有一个实用函数,它接受任意两种文档类型,并确定它们是否符合许多标准,如文档的类型、它们是否共享任何作者等。代码可以工作,但I’;如果可能的话,我想用Java Streams来解决这个问题

我目前通过使用以下代码解决此问题:

  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