简体   繁体   中英

Java-8 Streams: Convert List<{String,List<String>}> to Map<String, List<String>>

I have a Tag class which contains a list of Items

class Tag {

private String tagName
private List<String> items

}

I have a list of Tags in which each tag a list of items

List<Tag> tagList =   [
                       {"tagName": "popular", "items": ["Item1","Item2","Item3","Item4"]},
                       {"tagName": "expensive" , "items":  ["Item2","Item4","Item5"]},
                       {"tagName": "mostwanted", "items":  ["Item1","Item2","Item5"]}
                      ]

I wan to convert this to a map which have the items as key and tagName as values.

expected output:

{
    "Item1" : ["popular","mostwanted"],
    "Item2" : ["popular","expensive","mostwanted"],
    "Item3" : ["popular","mostwanted"],
    "Item4" : ["popular","expensive"],
    "Item5" : ["expensive","mostwanted"]
}

I tried various combination of stream/faltmap/groupingBy, but I didnt get the expected output. Can you please help. Thanks

You can flat the items using flatMap then create pair of item and tagName using SimpleEntry . Then grouping by item using groupingBy and map tagName to get list of tagName

Map<String, List<String>> tagMap = tagList.stream()
        .flatMap(t -> t.getItems()
                       .stream()
                       .map(item -> new AbstractMap.SimpleEntry<>(item, t.getTagName())))
        .collect(Collectors.groupingBy(m -> m.getKey(),
            Collectors.mapping(m -> m.getValue(), Collectors.toList())));

Here is a procedural way to go using new features from such as Map::computeIfPresent and Map::computeIfAbsent , but without :

Map<String, List<String>> map = new HashMap<>();
    tagList.forEach(tag -> {
        String tagName = tag.getTagName();
        tag.getItems().forEach(item -> {
            map.computeIfPresent(item, (k, v) -> { v.add(tagName); return v; });
            map.computeIfAbsent(item, k -> new ArrayList<>(Arrays.asList(tagName)));
   });
});

map.forEach((k, v) -> System.out.println(k + " " + v));

If you want to sort these items from Item1 to Item5 , use the different implementation:

Map<String, List<String>> map = new TreeMap<>();

Moreover, your expected output doesn't match as long as there is only one occurence of Item3 :

Item1 [popular, mostwanted]
Item2 [popular, expensive, mostwanted]
Item3 [popular]
Item4 [popular, expensive]
Item5 [expensive, mostwanted]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM