ShaneK
ShaneK

Reputation: 303

Returning adjacent keys from a TreeMap

Given the following TreeMap:

Map<Double, Integer> treeMap = new TreeMap<Double, Integer>() {{. 
        put("52.1", 1);
        put("53.4", 2); 
        put("57.1", 3); 
        put("59.4", 7); 
        put("60.2", 11); 
        put("71.6", 16)}};

What would be the best way to return the closest n matches (in both directions) for a given double? For instance, n=2 and "58.0" would return 53.4, 57.1, 59.4, 60.2

Upvotes: 1

Views: 687

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 338730

tl;dr

new TreeMap <>(
        Map.of(
                52.1d , 1 ,
                53.4d , 2 ,
                57.1d , 3 ,
                59.4d , 7 ,
                60.2d , 11 ,
                71.6d , 16
        )
)
.floorKey( 58.0d )     // Or call `.ceilingKey( 58.0d )`

See this code run live at IdeOne.com.

57.1

NavigableMap::lowerKey/higherKey

TreeMap is a NavigableMap.

The NavigableMap interface provides methods for retrieving adjacent keys (and entries).

Repeat the commands to fetch as many adjacent keys as you desire, until receiving a null.

Comparing keys

On second reading, it seems you do not have a key. You have a value you want to compare to keys in a map.

In this case, fetch a Set of all the keys in the map. NavigableMap extends SortedMap. So we can call SortedMap::keySet. The returned set iterates in sorted order.

Set< Double > set = map.keySet() ;

Make a List of that, to access individual elements by index.

List< Double > doublesListSorted = List.of( set.toArray() ) ;  // Get un-modifiable list.

Now you can loop the sorted list to compare values.

NavigableMap::floorKey/ceilingKey

Or, as dnault commented, we can ask the NavigableMap to compare key values for a nearest-match.

  • floorKey
    Returns the greatest key less than or equal to the given key, or null if there is no such key.
  • ceilingKey
    Returns the least key greater than or equal to the given key, or null if there is no such key.

Example code

Make an input map. We use Map.of initially for its convenient literal syntax. Then we feed that un-modifiable map to the constructor of TreeMap. Our literal input seen here happens to be sorted, but that is irrelevant, as the TreeMap constructor will sort the entries by key.

NavigableMap < Double, Integer > map =
        new TreeMap <>(
                Map.of(
                        52.1d , 1 ,
                        53.4d , 2 ,
                        57.1d , 3 ,
                        59.4d , 7 ,
                        60.2d , 11 ,
                        71.6d , 16
                )
        );

map.toString(): {52.1=1, 53.4=2, 57.1=3, 59.4=7, 60.2=11, 71.6=16}

Set our target to which we want the closest matches.

Double target = 58.0d;

Get the adjacent keys, next lower, and next higher.

Double nextLower = map.floorKey( target );
Double nextHigher = map.ceilingKey( target );

nextLower = 57.1 nextHigher = 59.4

See this code run live at IdeOne.com.


Notes:


Table of map implementations in Java 11, comparing their features

Upvotes: 3

Related Questions