Java collect nested stream of maps returning top level items

Viewed 173

I have the following model:

class Item {
    String name;
    ...
    List<SubItem> subItems;
}

class SubItem {
    String name;
    ...
    List<String> ids;
}

For every id in the subItem.ids I'd like to extract some top level parameters. For that I defined a custom tuple:

class AdditionalParams {
    private final String itemName;
    private final String subItemName;
    ...
}

The goal is to return a Map<String, AdditionalParams> where:

  • key: id in subItem.ids
  • value: AdditionalParams for this id

I assume ids are unique so there won't be any conflicts when adding elements to the Map.

My solution

I tried to use a flatMap with Collectors.toMap:

List<Item> allItems = ...
Map<String, AdditionalParams> result = allItems
    .stream()
    .flatMap(i -> i.getSubItems()
                   .stream()
                   .map(si -> si.getIds()
                                .stream()
                                .collect(
                                    Collectors.toMap(
                                        Function.identity(),
                                        id -> new AdditionalParams(i.getName(), si.getName())
                                    )
                                )
                   )
    )  // Stream< Map<String, AdditionalParams> >
    .collect(
        Collectors.toMap(m -> m.getKey(), m -> m.getValue())
    )

The problem is that the last line (.collect(Collectors.toMap(...) is not working (or I'm doing it wrong). I tried to follow this answer Convert List of Maps to single Map via streams but couldn't make it work either.

What am I doing wrong with my approach? How can I get a result of type Map<String, AdditionalParams>?

1 Answers

What you could do to fix that is to map the intermediate state to entries of a map instead and then collect them. This would go like --

Map<String, AdditionalParams> result = allItems
        .stream()
        .flatMap(item -> item.getSubItems().stream()
                .flatMap(subItem -> subItem.getIds()
                        .stream()
                        .map(id -> new AbstractMap.SimpleEntry<>(
                                id, new AdditionalParams(item.getName(),
                                subItem.getName())))))
        .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey,
                AbstractMap.SimpleEntry::getValue));
Related