Home > Mobile >  Find the Min of Max values in a Map<String, List<Integer>> without relying on for loops
Find the Min of Max values in a Map<String, List<Integer>> without relying on for loops

Time:05-27

I have a map of type HashMap<String, List<Integer>>.

I want to find the maximum value for each map entry, and in turn find the minimum of those maximum values.

I know this can be done using a couple of for loops. But was wondering if there's another way of doing it (maybe with streams?)

The final result I'm looking for is an integer.

Example:

HashMap<String, List<Integer>> values = new HashMap<>();

values.put("a", Arrays.asList(4, 8, 9, 10)); // max value is 10
values.put("b", Arrays.asList(20, 32, 1, 2)); // max value is 32
values.put("c", Arrays.asList(11, 50, 20, 6)); // max value is 50

// I need the min value out of the above maximums i.e. 10 (final answer)

CodePudding user response:

You can use the methods Collections.min and Collections.max

HashMap<String, List<Integer>> myMap = new HashMap<>();

Integer min = Collections.min(myMap.values().stream().map(Collections::max).collect(Collectors.toList()));

CodePudding user response:

I want to find the maximum value for each map entry and inturn find minimum of those maximum values.

Then IntSummaryStatistics is your new friend. This object is meant to provide such information as min and max values, the number of consumed elements, average and their total.

As a container for the result, we can use a map Map<String, IntSummaryStatistics> that will hold statistics of every value mapped to this value's key. For that we need a help of collectors flatMapping() and summarizingInt().

Then to get the smallest maximum, we should process the values of this map.

Map<String, List<Integer>> sourceMap = 
    Map.of("a", List.of(4, 8, 9, 10),    // max value is 10
           "b", List.of(20, 32, 1, 2),   // max value is 32
           "c", List.of(11, 50, 20, 6)); // max value is 50
        
Map<String, IntSummaryStatistics> statisticsByKey = sourceMap.entrySet().stream()
    .collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collectors.flatMapping(entry -> entry.getValue().stream(), // flatens each list
            Collectors.summarizingInt(Integer::intValue))          // creates IntSummaryStatistics object based on the values of each list
    ));
    
statisticsByKey.forEach((k, v)
    -> System.out.println(k   " -> min: "   v.getMin()   " max: "   v.getMax()));
        
int smallestMaximum = statisticsByKey.values().stream()
    .mapToInt(IntSummaryStatistics::getMax)
    .min()        // produces OptionalInt as a result
    .orElse(-1);  // returns a default value of `-1` if result is not present
    
System.out.println("smallestMaximum: "   smallestMaximum);

Output:

a -> min: 4 max: 10
b -> min: 1 max: 32
c -> min: 6 max: 50

smallestMaximum: 10

A link to the Online Demo

CodePudding user response:

Given a map

Hash<String, List<Integer>> values;

Find each list's max, then use IntStream's min() over those:

Integer minMax = values.values().stream()
  .map(Collections::max)
  .mapToInt(n -> n).min().getAsInt();

See live demo finding 10 from your sample data.


For the IntStream only version (probably more efficient), stream the values (ie the lists of integers), then find each list's max by converting each list to an IntStream and getting its max, then find min of those:

Integer minMax = values.values().stream()
  .mapToInt(v -> v.stream().mapToInt(n -> n).max().getAsInt())
  .min().getAsInt();

See live demo.

This assumes all lists are not empty and the map itself is not empty.


There is also a way that makes use of Collections.max(), but produces an Optional` which is slightly more obtuse way IMHO

Integer minMax = values.values().stream()
    .map(Collections::max)
    .collect(Collectors.minBy(Integer::compareTo)).get();

See live demo.

  • Related