I have a class Range and a comparator in Java:
class Range{
int start;
int end;
}
class RangeComparator implements Comparator<Range> {
@Override
public int compare(Range range1, Range range2) {
//implementation
}
}
and another class that that has a nested map;
class MyClass{
private static Map<String, Map<String, Map<Range, List<String>>>> nestedMap;
}
I need:
How to achieve that?
In C++, those can be achieved by sepcifying the comparator in the declaration of the nestedMap as below:
struct Comp {
const bool operator()(const Range& range1, const Range& range2) const {
// implementation
}
};
class MyClass{
// declare the nested map with the comparator Comp
map<string, map<string, map<Range, vector<string>, Comp>>> nestedMap;
};
I am wondering how to achieve the same in Java.
You can only initialize the outermost map directly, the inner maps are associated with a key and each key would have its own map as value. Unless you know the keys beforehand and initialize in advance, it's not possible.
About what you need:
the innermost map of the nestedMap to be a TreeMap that uses the RangeComparator to sort its keys
- you can't declare that the Map
will be a TreeMap
with specific comparator.You can make the nested map a TreeMap and range comparable
Map<String, Map<String, TreeMap<Range, List<String>>>> nestedMap;
...
class Range implements Comparable<Range> {
@Override
public int compareTo(Range other) {
//logic
}
}
This may be undesirable for your case due to a myriad reasons - Range should not have natural ordering, you should not bind to a concrete Map
implementation, the map can still be created with a different comparator so your order won't be followed, etc. The preferable solution in this case (and in principle) is to encapsulate the logic of creating this innermost map. See the example below how to do it.
the nestedMap is empty when an object of MyClass is created
- then nestedMap should not be static (this means it belongs to the class, not the instance).the innermost map has the property of using the specific comparator when an entry is inserted into the map
- this is already covered by the first requirement, when a TreeMap
is created with a Comparator
it sorts the entries by their keys according to the comparator, without a comparator they are sorted according to their natural ordering (and will throw ClassCastException
if the keys don't implement Comparable
).One of the ways to initialize the map on demand the exact way you need it, is to use Map.computeIfAbsent().
If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
As I said above this logic should be encapsulated and hidden from the outside world.
public class MyClass {
//random implementation to make it compile
private static final Comparator<Range> RANGE_COMPARATOR = Comparator.comparing(Range::start).thenComparing(Range::end);
private final Map<String, Map<String, TreeMap<Range, List<String>>>> nestedMap;
public MyClass() {
this.nestedMap = new HashMap<>();
}
public Map<Range, List<String>> getRangesMap(String key1, String key2) {
return nestedMap
.computeIfAbsent(key1, k -> new HashMap<>())
.computeIfAbsent(key2, k -> new TreeMap<>(RANGE_COMPARATOR));
}
}
I don't know the exact use case (you may need to get the map in a different way), but this shows the principle - now every Map<Range, List<String>>
you get from MyClass
will be a TreeMap
sorting entries according to your comparator.