Java Lambda Expression for Nested Loops with Conditional

Todd picture Todd · Apr 28, 2015 · Viewed 7.8k times · Source

I am new to lambda expressions and am trying to use them to reduce the following code to the lambda equivalent. I have looked into reduce and flatMap and forEach, as well as several other things, but I am obviously missing something because everything that I try is either syntactically incorrect or I don't have a reference for what I need.

I need to perform an analysis of each element against all other elements in a collection. I coded that as nested loops with a conditional. Once non-matching elements have been identified, a computation is done using both elements. Finally, I want a collection of results for each comparative computation.

So, here's the original code:

final List<Element> updated = new ArrayList<>(elements.size());

for (final Element first : elements) {
    Attribute newAttribute = first.getAttribute();

    for (final Element second : elements) {
        if (!first.equals(second)) {
            newAttribute = newAttribute.add(computeChange(first, second));
        }
    }
    final Element newElement = new Element(first.getEntry(), newAttribute, first.getValue());
    updated.add(newElement);
}

Then, I tried many variations of lambda expressions, the simplest of which is:

elements.parallelStream()
         .map(first -> new Element(first.getEntry(), first.getAttribute().add(
         computeChange(first, second)), first
         .getValue())).collect(Collectors.toList()));

Obviously, this is wrong as there is no reference to second available to me and no condition/filter for second being not equal to first.

How do I reduce this nested loop with conditional returning a collection to a lambda expression?

Any help here is greatly appreciated.

Answer

pgerstoft picture pgerstoft · Apr 28, 2015

Try:

elements.stream()
    .map(first -> {
       Attribute newAttribute = elements.stream().filter(second -> !first.equals(second))
                .map(second -> computeChange(first, second))
                .reduce(first.getAttribute(), (a, b) -> a.add(b))
                return new Element(first.getEntry(), newAttribute, first.getValue());
            }).collect(Collectors.toList()));