Java - get top 15 from HashMap by rule

2019-09-21 12:00发布

问题:

I would like to ask for help. Let's say I have HashMap with key-value like this:

String1 0.99
String2 0.98
String3 0.97
String4 0.98
String5 0.5
String6 0.4
String7 0.3
etc.

And I would like to save to array the top 15 entries by this formula: Math.abs(value - 0.5).

The counted values (by the formula) for this data would be:

String1 0.49
String2 0.48
String3 0.47
String4 0.48
String5 0
String6 0.1
String7 0.2

The values sorted

String1 0.49
String4 0.48
String2 0.48
String3 0.47
String7 0.2
String6 0.1
String5 0

And now I would like to have array, where index would be the order and value the original value, like this:

array[0] = 0.99
array[1] = 0.98
array[2] = 0.98
array[3] = 0.97
array[4] = 0.3
array[5] = 0.4
array[6] = 0.5 

Thanks everyone for help

Any help would be appreciated. Thank You

回答1:

You can use Java 8 stream API:

List<Double> result = map.values().stream()
        .map(value -> Math.abs(value - 0.5))
        .sorted()
        .limit(15)
        .collect(toList());


回答2:

First option is to iterate over the whole map and find your values - perhaps throw it into an array and use an O(n * log n) sort algorithm or 15*O(n) walks over it.

Can you drop the condition that the keys are unique? Then work with ordered pairs (String, float) and write a customer Comparator that implements your rule on the "float" value, and use a SortedSet.

There may be a solution involving BiMap, I'm not sure.



回答3:

OK. So you have a map, but you only care about its values. So let's start by getting the values out of the map:

map.values()

Then you want to sort these values. So you need a comparator. This comparator should sort by Math.abs(value - 0.5)

Comparator<Float> comparator = 
    Comparator.comparing((Float value) -> Math.abs(value - 0.5F));

But the values leading to the largest difference should come first, rather than last. So let's reverse the comparator:

Comparator<Float> comparator = 
    Comparator.comparing((Float value) -> Math.abs(value - 0.5F))
              .reversed();

Now you need to apply that comparator, and only take the 15 first values:

Comparator<Float> comparator = 
    Comparator.comparing((Float value) -> Math.abs(value - 0.5F))
              .reversed();

List<Float> top15 = map.values()
                       .stream()
                       .sorted(comparator)
                       .limit(15) 
                       .collect(Collectors.toList());

Or, if you really want an array rather than a List:

Float[] top15 = map.values()
                   .stream()
                   .sorted(comparator)
                   .limit(15) 
                   .toArray(Float[]::new);