2015-04-28 12 views
11

Jestem nowy w wyrażeniach lambda i próbuję ich użyć do zredukowania następującego kodu do odpowiednika lambda. Spojrzałem na zmniejszenie i flatMap i forEach, a także kilka innych rzeczy, ale oczywiście brakuje czegoś, ponieważ wszystko, co próbuję, jest albo niepoprawne syntaktycznie, albo nie mam odniesienia do tego, czego potrzebuję.Wyrażenie Java Lambda dla zagnieżdżonych pętli z warunkowym

Potrzebuję wykonać analizę każdego elementu względem wszystkich innych elementów w kolekcji. Zakodowałem to jako pętle zagnieżdżone warunkowe. Po zidentyfikowaniu niezgodnych elementów obliczenia są wykonywane przy użyciu obu elementów. Wreszcie, chcę zbiór wyników dla każdego obliczenia porównawczego.

Więc oto oryginalny kod:

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

Następnie próbowałem wiele odmian wyrażeń lambda, z których najprostsza jest:

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

Oczywiście, to jest źle, jak tam nie ma odniesienie do drugiego dostępnego mi i bez warunku/filtra dla drugiego nie będącego równym pierwszemu.

Jak zmniejszyć tę zagnieżdżoną pętlę warunkowym zwracaniem kolekcji do wyrażenia lambda?

Każda pomoc tutaj jest bardzo doceniana.

+3

Jest to trudne, ponieważ Twój 'newAttribute = newAttribute.add (...)' aktualizacje nie są parallelizable. Byłoby łatwiej, gdybyś mógł zebrać wszystkie wyniki "computeChange", a następnie utworzyć atrybut "Attribute" (lub "Element") z tego agregatu. –

+0

Po prostu zostawiłbym taki, jaki jest. –

+0

Co zwróci 'computeChange'? "Element", "Atrybut" lub liczba? –

Odpowiedz

3

Spróbuj:

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())); 
+4

Nie sądzę, że '.foreach (newAttribute :: add);' będzie działać, ponieważ 'add' wydaje się tworzyć nowy atrybut. Może jednak "zmniejszyć" zadziała. –

+0

@tobias_k the foreach zgłasza błąd: Metoda foreach (Attribute :: add) jest niezdefiniowana dla typu Stream . Korzystanie z redukcji eliminuje błąd. – Todd

+0

pgerstoft, @tobias_k Potrzebowałem zmienić argument foreach/reduce, aby być atrybutem: dodać inaczej Otrzymałem błąd "Atrybut typu nie definiuje add (Attribute, Attribute), który ma zastosowanie tutaj". Jednak nie przechodzę testów jednostkowych, więc nie sądzę, że powtarzana aktualizacja/add działa poprawnie. Mam zamiar dalej go szturchać, ale jeśli masz jakieś sugestie, bardzo chciałbym je usłyszeć. – Todd