Search code examples
javajava-stream

Sort Map using java streams


How to sort a map with the key first and sort the values as well.

Map<String, List<String>> myMap = new HashMap<>();
myMap.put("Apple", Arrays.asList("iphone", "imac"));
myMap.put("Samsung", Arrays.asList("galaxys", "galaxyz"));
myMap.put("LG", Arrays.asList("ultra", "tab"));

//sort logic
Sort with the key first {Apple, LG, Samsung} and then sort the values based on the key.

Result:

imac, iphone, tab, ultra, galaxys, galaxyz

Solution

  • It's easier to work out stream problems by making a plan. An example one for this problem would be:

    1. Get a stream from the map using Key, Value pairs (Stream<Map.Entry<String, List<String>>>)
    2. Sort by the keys
    3. Get the value (lists) from the sorted keys; to get a stream of lists in the correct order (Stream<List<String>>)
    4. Sort the lists
    5. Combine the elements of every list into one stream (Stream<String>)
    6. Collect the stream into the final list (List<String>)

    You'd first have to convert the map to an entrySet to allow you to stream over the Map.Entry entries. Then we can get the lists sorted via the map key with .sorted(Map.Entry.comparingByKey()) and .map(Map.Entry::getValue).

    Once we have the lists in sorted order, the elements within are not sorted. So we then need to flatten them (go from a Stream<List<String>> to Stream<String> containing the elements of the lists) in sorted order: .flatMap(list -> list.stream().sorted())

    Resulting in the code:

    List<String> result = myMap.entrySet().stream() // Step 1
        .sorted(Map.Entry.comparingByKey())         // Step 2
        .map(Map.Entry::getValue)                   // Step 3
        .flatMap(list -> list.stream().sorted())    // Step 4+5
        .collect(Collectors.toList());              // Step 6
    

    You can also skip the mapping from Map.Entry::getValue, doing .flatMap(entry -> entry.getValue().stream().sorted()) directly, but it's a bit less clear what's going on.