Search code examples
javalambdajava-streamtreemap

Finding all max values in (tree)map with streams and lambda in java


So I have to find the max value(s) in a map in java with streams and lambda. Finding one max value is not a problem, but how can I find multiple? Example: Treemap<String, Integer> with elements "e" = 2, "i" = 1, "a" = 2, My current solution gives me "a" = 2, but I want "a" = 2, "e" = 2

My code:

Map<String, Integer> frequencies = new Treemap<>();
frequencies.put("e", 2);//I don't put the values in like this but it'll do to test
frequencies.put("i", 1);
frequencies.put("a", 2);
Optional<Map.Entry<String, Integer>> maxEntry = frequencies.entrySet().stream()
        .max(Map.Entry.comparingByValue());//frequencies is the TreeMap<String, Integer>
//I know this only searches one max value, here's my other attempt:
try (Stream<Map.Entry<String, Integer>> stream = frequencies.entrySet().stream()) {
      stream
          .sorted(Map.Entry.comparingByValue())
          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k, v) -> k, LinkedHashMap::new));
//I don't know what to do here, I somehow would have to get the result into a new list, but it still only returns one result
    }

Please let me know if im doing anything wrong.


Solution

  • So I have to find the max value(s) in a map in java with streams and lambda.

    Here is one way to do it without a TreeMap. It does a frequency count of containing Entries.

    Map<String, Integer> map = Map.of("z", -1, "b", 0, "r", -2,
            "s", 0, "j", 1, "a", 2, "i", 1, "e", 2);
    
    Optional<Entry<Integer, List<Entry<String,Integer>>>> opt = map.entrySet()
            .stream()
            .collect(Collectors.groupingBy(Entry::getValue))
            .entrySet().stream().max(Entry.comparingByKey());
    
    System.out.println(opt.isPresent() ? opt.get().getValue() : "Empty List");
    
    

    Prints

    [a=2, e=2]
    

    And just for fun you can bypass the initial map and create a stream of entries. In reality, when you create your intitial Map you are creating Entry objects so no additional map overhead is involved here.

            
    Builder<Entry<String, Integer>> entryStream = Stream.builder();
    
    entryStream.add(Map.entry("b", 0));
    entryStream.add(Map.entry("r", -2));
    entryStream.add(Map.entry("s", 0));
    entryStream.add(Map.entry("j", 1));
    entryStream.add(Map.entry("a", 2));
    entryStream.add(Map.entry("i", 1));
    entryStream.add(Map.entry("e", 2));
    
    

    At this point, it's the same as before except the stream is ready to invoke.

    Optional<Entry<Integer, List<Entry<String, Integer>>>> opt =
                    entryStream.build()
                            .collect(Collectors
                                    .groupingBy(Entry::getValue))
                            .entrySet().stream()
                            .max(Entry.comparingByKey());
            
    System.out.println(opt.isPresent() ? opt.get().getValue() :
                    "Empty List");
            
    

    Prints as before

    [a=2, e=2]