是否可以使用Stream API替换不同集合上的嵌套循环

时间:2018-08-01 09:55:43

标签: java java-stream nested-loops

我想知道是否可以在 Java 8 中使用java.utils.stream重写嵌套的for循环?

这是我正在使用的示例数据类型:

class Folder {
  private final String name;
  private final Integer itemCound;

  Folder(String name, Integer itemCount) {
    this.name = name;
    this.itemCount = itemCount;
  }

  public String getName() { return this.name; }
  public Integer getItemCount() { return this.itemCount; }
}

这里的代码在起作用:

List<Folder> oldFolders = new ArrayList<>();
List<Folder> newFolders = new ArrayList<>();

// Fill folder collections with sample data...
oldFolders.add(new Folder("folder1", 2));
oldFolders.add(new Folder("folder2", 4));
newFolders.add(new Folder("folder1", 0));
newFolders.add(new Folder("folder2", 100));

// This part should be rewrited using streams
for (Folder newFolder : newFolders) {
  for (Folder oldFolder : oldFolders) {
    if (newFolder.getName().equals(oldFolder.getName()) 
        && !newFolder.getItemCount().equals(oldFolder.getItemCount())) {
      // do stuff...    
    }
  }
}

P.S:我在 SO 上看到了其他问题,但所有这些问题都有一个集合或一个具有自己的嵌套集合的集合,而不是像我的示例中的两个不同集合。

谢谢!

4 个答案:

答案 0 :(得分:1)

是的,您可以:

newFolders.forEach((newFolder) -> {
    oldFolders.forEach((oldFolder) -> {
        if (newFolder.getName().equals(oldFolder.getName()) 
        && !newFolder.getItemCount().equals(oldFolder.getItemCount())) {
           // do stuff...    
        }
     })
  })

编辑:但是正如@Kayaman在下面的评论中提到的,这不一定比仅使用嵌套的for循环更好。

当您应该或不应该考虑使用流时,这是一本不错的书:

In Java, what are the advantages of streams over loops?

答案 1 :(得分:1)

除非可以并行化第一个迭代(在此示例中进行了评论),否则这并没有太大的改善

List<String> oldList = new ArrayList<>();
List<String> newList = new ArrayList<>();

oldList
    //.stream()
    //.parallel() 
    .forEach(s1 ->
    newList
        .stream()
        .filter(s2 -> s1.equals(s2)) //could become a parameter Predicate
        .forEach(System.out::println) //could become a parameter Consumer
);

if和他的filter代替Predicate,然后对其执行一个方法。

这将提供一种动态解决方案,为PredicateConsumer方法提供不同的filterforEach。那将是进行此转换的唯一原因。

答案 2 :(得分:0)

我不知道您的doStuff会做什么。但是像这样的事情会起作用。

Map<String, List<Folder>> oldFoldersByName = oldFolders.stream()
        .collect(Collectors.groupingBy(Folder::getName));
newFolders.stream()
    .filter(f -> oldFoldersByName.get(f.getName()).size() > 0 && oldFoldersByName
        .get(f.getName()).stream().allMatch(of -> !of.getItemCount().equals(f.getItemCount()))).map(// do stuff...);

如果doStuffFunction,那么map将起作用。如果它是Consumer,则可以相应地使用forEach。不幸的是,我没有自由知道这个doStuff的作用,这对我来说只是一个黑匣子。

答案 3 :(得分:0)

尝试一下:

newFolders.stream().filter(newFolder -> 
            oldFolders
                    .stream()
                    .anyMatch(oldFolder-> 
                            newFolder.getName().equals(oldFolder.getName()) &&
                                    !newFolder.getItemCount().equals(oldFolder.getItemCount())
                    )).forEach(folder -> {
                        //dostuff
    });