2015-03-25 9 views
5

W jaki sposób można skorygować sumę za pomocą interfejsu API stream z zagnieżdżonymi pętlami foreach, z których każdy ma stan filtra?Jak sumować wartości w zagnieżdżonych pętlach foreach?

//java7 
Double sum = null; 
for (FirstNode first : response.getFirstNodes()) { 
    if (first.isValid()) { 
     for (SndNnode snd : first.getSndNodes()) { 
      if (snd.getType() == NodeType.AMOUNT) { 
       sum += snd.getAmount(); 
       break; 
      } 
     } 
    } 
} 

//java8 
response.getFirstNodes().stream().filter(first -> first.isValid()).mapToDouble(???).sum(); 

Moja SND pętla foreach będzie:

first.getSndNodes().stream().filter(snd -> snd.getType() == NodeType.AMOUNT).mapToDouble(snd -> snd.getAmount()).findFirst().sum(); 

Jak mogę teraz zintegrować pętlę foreach SND do pierwszego, aby uzyskać globalną sumę zagnieżdżonych list?

+0

Myślę, że instrukcja 'break;' jest zbędna –

+0

Nie, jeśli 'getSndNodes()' zwraca naprawdę dużą listę i chcę uzyskać tylko pierwszy/jedyny wynik. Ale oczywiście dotyczy to tylko bardzo dużych list i przez większość czasu nie będzie miało żadnego wpływu. – membersound

Odpowiedz

8

można użyć flatMap:

response.getFirstNodes() 
     .stream() 
     .filter(first -> first.isValid()) 
     .flatMap(first -> first.getSndNodes().stream()) 
     .filter(snd -> snd.getType() == NodeType.AMOUNT) 
     .mapToDouble(snd -> snd.getAmount()) 
     .sum(); 

Nie jestem pewien, czy to jest zamierzone w break; swoje oryginalny kod.


ze stwierdzeniem break;, powinna ona wyglądać tak:

response.getFirstNodes() 
       .stream() 
       .filter(first -> first.isValid()) 
       .map(first -> first.getSndNodes().stream().filter(snd -> snd.getType() == NodeType.AMOUNT).findFirst()) 
       .filter(Optional::isPresent) 
       .mapToDouble(opt -> opt.get().getAmount()) 
       .sum(); 

W zasadzie dla każdego FirstNode przetestować czy to ważne, a następnie zmapować każdy FirstNode do strumienia swoich SndNode s, dla których znajdziesz pierwszą, która ma typ NodeType.AMOUNT. Musisz wtedy filtrować, aby uzyskać tylko Opcjonalne opcje, które nie są puste, a dla nich zawierają one SndNode, które zawierają odpowiednią kwotę.

+0

"Przerwa" ma na celu iterację dużej listy i może zapewnić, że mój stan będzie zawsze pasował tylko do jednego elementu. Tak więc, jeśli zostanie znaleziona najbardziej wewnętrzna pętla powinna się zepsuć. Ale z twoich odpowiedzi zakładam, że to wewnętrzne zwarcie nie jest możliwe w strumieniu api? – membersound

+2

OK, ale potem twoja druga wersja - każde tłumaczenie nie jest tym samym, co oryginalny kod, ponieważ zsumuje wszystkie wartości każdej instancji snd, które są AMOUNT zamiast pierwszej wartości w oryginalnym kodzie. –

+0

Dzięki, dodałem 'findFirst()' do mojego postu, aby było jasne. – membersound

2

Można użyć flatMap tworzyć pojedynczy strumień wszystkich wewnętrznych list:

response.getFirstNodes() 
     .stream() 
     .filter (first -> first.isValid()) 
     .flatMap (first -> first.getSndNodes().stream()) 
     .filter(snd -> snd.getType() == NodeType.AMOUNT) 
     .mapToDouble(snd -> snd.getAmount()) 
     .sum(); 
2

Możesz użyć .flatMap() węzłów zagnieżdżonych. Na przykład:

response.getFirstNodes().stream() 
         .filter(FirstNode::isValid) 
         .flatMap(first -> first.getSndNodes().stream()) 
         .filter(snd -> snd.getType == NodeType.AMOUNT) 
         .mapToDouble(SndNode::getAmount) 
         .sum(); 
4

Twoja próba jest zbliżony do odpowiedniego rozwiązania

response.getFirstNodes().stream() 
.filter(FirstNode::isValid) 
.mapToDouble(first -> 
    first.getSndNodes().stream() 
     .filter(snd -> snd.getType() == NodeType.AMOUNT) 
     .mapToDouble(snd -> snd.getAmount()) 
     .findAny().orElse(0)) 
.sum(); 

Jeżeli jesteś pewien, że istnieje co najwyżej jeden mecz w wewnętrznym strumieniu, można wykorzystać findAny jak nie ma wymogu na zamówienie. Użyłem najprostszego rozwiązania, aby poradzić sobie z ewentualnym brakiem meczu, zastępując go 0, który jest przezroczysty dla sum i oszczędza nam dodatkowego filtrowania.

+1

Ten też jest miły ... +1 –