Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Hash Map

I have a map Map<String, List<Double> and I would like to find the maximum (or minimum) value in all of the lists. The function should return the maximum (or minimum) value and the key belonging to that value.

The signature may be

public static Pair<String,Double> getKeyValue(Map<String, List<Double>> map, BinaryOperator<Double> function)

which gets the map and the function Double::max or Double::min

How can i implement this efficiently (and beautifully) using java 8, stream api ?

like image 887
Omer Avatar asked Oct 12 '14 16:10

Omer


2 Answers

A BinaryOperator is not a good specification for that task, it is straight-forward to use in a reduction to produce the appropriate value, e.g. minimum or maximum, however it is not suitable for returning an associated value like the Map’s key value. Using it this way implies that the implementation has to perform additional operations to find out, what the BinaryOperator actually did in order to select the correct key value during the reduction. Even worse, it can’t guaranty that the BinaryOperator does something that allows to perform this kind of reduction, e.g. the operator might return a value which is neither of its arguments.

For such a task, a Comparator is the better choice as it is designed for specifying an ordering and perform related operations like finding maximum and minimum. An implementation might look like this:

public static Pair<String,Double> getMinimumKeyValue(
    Map<String, List<Double>> map, Comparator<Double> function) {

    return map.entrySet().stream()
        .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get()))
        .min(Comparator.comparing(Pair::getRight, function)).get();
}

It is named getMinimumKeyValue as it will return the minimum key/value pair when you pass in Comparator.naturalOrder().

But you can get the maximum as well by passing Comparator.reverseOrder().

And it’s easy to modify to support a broader range of use cases:

public static <K,V> Pair<K,V> getMinKeyValue(
    Map<K, ? extends Collection<V>> map, Comparator<? super V> function) {

    return map.entrySet().stream()
        .map(e->new Pair<>(e.getKey(), e.getValue().stream().min(function).get()))
        .min(Comparator.comparing(Pair::getRight, function)).get();
}

This still works for getting a Pair<String,Double> out of a Map<String, List<Double>> but can do a lot more…

like image 58
Holger Avatar answered Sep 21 '22 11:09

Holger


You can try this :

public static Pair<String,Double> getKeyValue(Map<String,List<Double>> map,
        BinaryOperator<Double> function) {
        return map.entrySet().stream()
            .map(e -> new Pair<String,Double>(e.getKey(),e.getValue().stream().reduce(function).get()))
            .reduce((p1,p2) -> function.apply(p1.getValue(),p2.getValue()).equals(p1.getValue()) ? p1 : p2)
            .get();
}

Explanation :

First, you associate each Entry<String,List<Double>> to a Pair<String,Double> where the value is the min (or max) of the list and the key remains the same, then you compare each Pair<String,Double> to find the one which has the lowest (or highest) value.

like image 23
Dici Avatar answered Sep 21 '22 11:09

Dici