32

Let's assume that we have a list of countries: List<Country> and each country has a reference to a list of its regions: List<Region> (e.g. states in the case of the USA). Something like this:

USA
  Alabama
  Alaska
  Arizona
  ...

Germany
  Baden-Württemberg
  Bavaria
  Brandenburg
  ...

In "plain-old" Java we can count all regions e.g. this way:

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

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

Is it possible to achieve the same goal with Java 8 Stream API? I thought about something similar to this, but I don't know how to count items of nested lists using count() method of stream API:

countries.stream().filter(country -> country.getRegions() != null).???
1
  • 2
    IMHO this @fabian solution should be preferred. List::size is an O(1) operation whilst using a flatMap on every list is an O(n) operation. Commented Oct 24, 2015 at 12:21

3 Answers 3

68

You could use map() to get a Stream of region lists and then mapToInt to get the number of regions for each country. After that use sum() to get the sum of all the values in the 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();

Note: The benefit of using getRegions before filtering is that you don't need to call getRegions more than once.

Sign up to request clarification or add additional context in comments.

4 Comments

Side note, you can use Objects::nonNull instead of rs -> rs != null
Is there a way to get country name and its number of regions? instead of total number of regions across all countries?
Is there a way to return a list containing sizes of individual regions instead?
@ashwanikumar If you do not use sum in the end, and use map instead of mapToInt, you get an Stream<Integer> which could be converted to a list using the appropriate collector.
10

You may map each country to number of regions and then reduce result using sum:

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

1 Comment

.reduce(Integer::sum) :)
1

You could even use flatMap() like:

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>

1 Comment

Disclaimer: This approach may be slower if Java enumerates the Region objects in the stream. In this case, it will be better to go with @fabian's solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.