javaandroidlistdictionarymultiple-value

How to turn a List<Map<String, String>> with similar keys to a Map<String,List<String>>?


I have the following List -

private MiniProductModel selectedProduct;
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_product_page);
        mPresenter = new ProductPagePresenter(this);
        mPresenter.initViews();
        mPresenter.initProductData();

        Gson gson = new Gson();
        List<Map<String, String>> attributesList = selectedProduct.getAttributesList(); //this is the list

So the raw value of what I am getting is the following -

[{value=Pink, key=Color}, {value=Yellow, key=Color}]

enter image description here

The final result that I want to achieve is a map containing one or more keys with each of them having a list of value Strings. For example - the product I have shown you here has 2 different colors, so I need the map to have one key named Color and a value list with multiple String values.

How can I turn my list to the wanted map?

edit -

here is my current result with Wards solution -

{value=[Sensitive Skin, Normal Skin, Combination Skin, Oily Skin, MEN], key=[Skin Type, Skin Type, Skin Type, Skin Type, Skin Type]}

The keys have been duplicated. why ?

enter image description here


Solution

  • Stream (>= Java 8)

    This can be done quite elegantly by using a Stream for the List, flatMap to the entries of the Maps, and then collect using the groupingBy collector:

    // Note that Map.of/List.of require Java 9, but this is not part of the solution
    List<Map<String, String>> listOfMaps = List.of(
            Map.of("1", "a1", "2", "a2"),
            Map.of("1", "b1", "2", "b2")
    );
    
    final Map<String, List<String>> mapOfLists = listOfMaps.stream()
            .flatMap(map -> map.entrySet().stream())
            .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())));
    
    mapOfLists.forEach((k, v) -> System.out.printf("%s -> %s%n", k, v));
    

    The output is

    1 -> [a1, b1]
    2 -> [a2, b2]
    

    For loop

    If streams are not an option, you could use a plain old for loop, e.g.

    final Map<String, List<String>> mapOfLists = new HashMap<>();
    for (Map<String, String> map : list) {
        for (Entry<String, String> entry : map.entrySet()) {
            if (!mapOfLists.containsKey(entry.getKey())) {
                mapOfLists.put(entry.getKey(), new ArrayList<>());
            }
            mapOfLists.get(entry.getKey()).add(entry.getValue());
        }
    }