0

I was wondering if it's possible to rewrite nested for loops using java.utils.stream in Java 8?

Here is a sample data type I'm working with:

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; }
}

Here's code in action:

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: I've seen other questions on SO, but all of them had 1 collection or a collection with it's own nested collection instead of two different collections like in my example.

Thanks in advance!

pavjel
  • 486
  • 10
  • 25
  • Not in any way that would *improve* the code. – Kayaman Aug 01 '18 at 10:01
  • 2
    "_//This part should be rewrited using streams_" I don't really agree, this is actually simple, readable and efficient. Now what you can do is change the `if` to use a `filtre` but this can be done just using `stream` on `oldFolders`. – AxelH Aug 01 '18 at 10:05
  • @AxelH, my concern was, maybe there is more efficient way to rewrite this part (because two `for` loops will iterate more times that are actually needed - in cases when folder names aren't equal maybe we could skip iteration). – pavjel Aug 01 '18 at 10:55
  • In that case, you need to be more specific on the requirement, is there more than one occurrence possible, is the list sorted, how big can it be. This is currently a O(n2) but with sorted list this could be done in O(n). – AxelH Aug 01 '18 at 15:19

3 Answers3

1

Yeah you can:

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

EDIT: But as @Kayaman mentions in the comments below this is not necessarily better than just using nested for loops.

This is a good read for when you should and shouldn't consider using streams:

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

Plog
  • 9,164
  • 5
  • 41
  • 66
  • 2
    Note that this is essentially the same as the for loops in the question, except now you've got some lambdas in the mix. This is in no way **better**, and due to the additional lambdas it's actually a bit worse if you get down to the bytecode. – Kayaman Aug 01 '18 at 10:04
  • Thanks for the article, @Plog – pavjel Aug 01 '18 at 10:51
1

That not much of an improvement to be fair unless if you can parallelize the first iteration (commented in this example)

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
);

Replacing the if with a filter and his Predicate then executing a method on it.

This would give a solution that can be dynamic providing different Predicate and Consumer to the filter and forEach method. That would be the only reason to work on this conversion.

AxelH
  • 14,325
  • 2
  • 25
  • 55
0

Try with this:

newFolders.stream().filter(newFolder -> 
            oldFolders
                    .stream()
                    .anyMatch(oldFolder-> 
                            newFolder.getName().equals(oldFolder.getName()) &&
                                    !newFolder.getItemCount().equals(oldFolder.getItemCount())
                    )).forEach(folder -> {
                        //dostuff
    });
GolamMazid Sajib
  • 8,698
  • 6
  • 21
  • 39