2015-10-24 3 views
8

Załóżmy, że mamy listę krajów: List<Country>, a każdy kraj ma odniesienie do listy regionów: List<Region> (np. Stany w przypadku USA). Coś takiego:Java Stream API - policz pozycje zagnieżdżonej listy

USA 
    Alabama 
    Alaska 
    Arizona 
    ... 

Germany 
    Baden-Württemberg 
    Bavaria 
    Brandenburg 
    ... 

W "zwykłej" Jawie możemy liczyć wszystkie regiony, np. w ten sposób:

List<Country> countries = ... 
int regionsCount = 0; 

for (Country country : countries) { 
    if (country.getRegions() != null) { 
     regionsCount += country.getRegions().size(); 
    } 
} 

Czy można osiągnąć ten sam cel dzięki API Java 8 Stream? Myślałem o czymś podobnym do tego, ale nie wiem jak liczyć elementów zagnieżdżonych list używając count() metodę strumienia API:

countries.stream().filter(country -> country.getRegions() != null).??? 
+2

IMHO to @fabian rozwiązanie powinno być korzystne. 'List :: size' to operacja' O (1) 'podczas gdy użycie' flatMap' na każdej liście jest operacją 'O (n)'. – Flown

Odpowiedz

17

Można użyć map() dostać Stream list regionu, a następnie do mapToInt uzyskać liczbę regionów dla każdego kraju. Po tym wykorzystania sum() aby uzyskać sumę wszystkich wartości w IntStream:

countries.stream().map(Country::getRegions) // now it's a stream of regions 
        .filter(rs -> rs != null) // remove regions lists that are null 
        .mapToInt(List::size) // stream of list sizes 
        .sum(); 

Uwaga: korzyść używając getRegions przed filtracja jest to, że nie trzeba zadzwonić getRegions więcej niż jeden raz.

+5

Nota boczna, możesz użyć 'Objects :: nonNull' zamiast' rs -> rs! = Null' – Tunaki

4

można mapować każdy kraj wielu regionach, a następnie zmniejszyć wynik stosując sumę:

countries.stream() 
    .map(c -> c.getRegions() == null ? 0 : c.getRegions().size()) 
    .reduce(0, Integer::sum); 
+3

.reduce (Integer :: sum) :) –

+0

Rozwiązałem mój problem! – Daria

0

Można nawet użyć flatMap() jak:

countries.stream().map(Country::getRegions).flatMap(List::stream).count(); 

where, 

map(Country::getRegions) = returns a Stream<List<Regions>> 
flatMap(List::stream) = returns a Stream<Regions>