Home > OS >  Convert nested loops into a Stream
Convert nested loops into a Stream

Time:07-07

I want to replace nested for loops in the following code with streams:

private boolean check(St st) {
    List<Co> prereqs = getCoPrereqs();
    
    for (Co prereq : prereqs) {
        
        List<En> stEns = st.getEns();
        boolean flag = false;
        
        for (En en : stEns) {
            if (en.getCo().equals(prereq) && en.getGr() != null) {
                if (en.hasPassedCo()) {
                    flag = true;
                }
            }
            if (!flag)
                return false;
        }
    }
    return true;
}

The two loops and the variable flag is causing confusion. I am not sure if this can be converted to streams totally.

CodePudding user response:

I have simplified your code somewhat by doing the following:

  • removing the boolean flag. It isn't necessary.
  • get the List<En> just one time outside of the Prereq loop. You can reiterate the original as often as necessary.

The major difference is to check for a false return from en.hasPassedCo() and return false immediately. Once the iterations are complete, then return true.

private boolean check(St st) {
        List<Co> prereqs = getCoPrereqs();
        
        List<En> stEns = st.getEns();

        for (Co prereq : prereqs) {           
            for (En en : stEns) {
                if (en.getCo().equals(prereq) && en.getGr() != null) {
                    if (!en.hasPassedCo()) {
                        return false;
                    }
                }
            }
        }
        return true;
}

I'm not certain that streams would improve this (at least not knowing more about the relationships of the fields to each other). Also, it doesn't make sense how Co relates to en.getCo. Seems to me that something like prereqs.contains(en.getCo()) would be more appropriate.

CodePudding user response:

Probably, you can use nested streams with allMatch.

I'm saying "probably" because I can't be sure that the code you've proved does what expected, types name are not self-explanatory at all (names in the code matter a lot) and you have not accompanied the code with any explanations.

If I understood your code correctly, you need to validate every Co object returned by getCoPrereqs() and that entails checking each Co object against En object from a List<En> which should be extracted from the method parameter.

That's how it might look like:

private boolean check(St st){
    
    return getCoPrereqs().stream()
        .allMatch((Co prereq) -> st.getEns().stream()
            .allMatch((En en) -> en.getCo().equals(prereq)
                            && en.getGr() != null
                            && en.hasPassedCo()
                     ));
}

For readability reasons (to make it more easier to compare stream with loops), I've used explicitly typed lambda expressions (the common practice is to omit types for brevity and let the type inference do the job).

  • Related