Search code examples
javajava-streamnested-loopsflatmap

flatMap triple nested streams


I'm trying to flatMap and get a result of list of Strings from three Lists. I somehow was able to do by the following code. The code is working but somehow I feel I have over complicated it. Can someone please give me some advice which can improve it in a better way

countries.stream()
    .map(country -> titles.stream()
        .map(title -> games.stream()
            .map(game -> Arrays.asList(game, country + "_" + title + "_" + game))
            .collect(toList()))
        .collect(toList()))
    .collect(toList())
    .stream()
    .flatMap(Collection::stream)
    .flatMap(Collection::stream)
    .flatMap(Collection::stream)
    .collect(Collectors.toSet());

For clarification of the logic, a traditional approach would look like:

Set<List<String>> results = new HashSet<>();
for (String country : countries) {
    for (String title : titles) {
        for (String game : games) {
            results.add(Arrays.asList(game, country + "_" + title + "_" + game));
        }
    }
}

Solution

  • You can do this in two steps:

    first create concatenation of countries and titles list:

    List<String> countriesTitle = countries.stream()
                .flatMap(country -> titles.stream()
                        .map(title -> country + "_" + title))
                .collect(Collectors.toList());
    

    then by previous result create list of concatenation country+"_"+title+"_"+game string:

    Stream.concat(games.stream(),
                        games.stream()
                              .flatMap(game -> countriesTitle.stream()
                                    .map(countryTitle -> countryTitle + "_" + game)))
             .collect(Collectors.toList());
    

    Updated answer:

    games.stream()
          .flatMap(game -> countries.stream()
                   .flatMap(country -> titles.stream()
                       .flatMap(title -> Stream.of(game, country + "_" + title + "_" + game))))
           .collect(Collectors.toSet());