Re: How to use java.util.Map in a more Perl like way.
robertjparks@gmail.com wrote:
Hi, I make extensive use of N-dimensional Maps in my code and would
like to find out if there is a way to manipulate them in a more
Perlish fashion. For example, say I have 2D map and I want to write
all the way through to the end. My code else up looking like this:
Map<String, Map<String,String>> map = new HashMap<String,
Map<String,String>>();
String key1= "key1";
String key2="key2";
String val="val";
// write to the structure building it up as you go
if(!map.containsKey(key1)) map.put(key1,new HashMap<String,String>());
if(!map.get(key1).containsKey(key2)) map.get(key1).put(key2,val);
In perl, you don't have to build up and walk through the structure in
order to write to it. For example, this would suffice:
my %map=();
my $key1= "key1";
my $key2="key2";
my $val="val";
# write to the structure in 1 shot
map{$key1}{$key2}=$val
To avoid having to "walk through and build up the structure" every
time I write to it, I wrote a static MapUtils to do the it. You can
say I am lazy here but the walking code blows out really fast when you
have an 5 level deep Map and I like to keep things short and neat.
public MapUtils{
public static put(Map<String,Map<String,String>> map, String key1,
String, key2,String, val){
if(!map.containsKey(key1)) map.put(key1,new
HashMap<String,String>());
if(!map.get(key1).containsKey(key2)) map.get(key1).put(key2,val);
}
}
Now I can just say:
MapUtils.put(map, key1, key2, val);
Which make my code much more readable.
Now here is where I need help!
How do I write MapUtils.put() so that it can take a Map<?,?> of any
number of dimensions and types and a list of N-keys and 1 value of any
type? I tried messing around with generics and wildcards but didn't
get too far. Maybe what I want to do is not possible. If this is the
case, I would like to hear why.
Instead of your put, you could write a static get method that creates if
necessary.
import static collection.HashMaps.get;
....
Map<String,Map<String,String>> map2;
Map<String,Map<String,Map<String,String>>> map3;
...
get(map2, key1).put(key2, value);
get(get(map3, key1), key2).put(key3, value);
....
package collection;
public final class HashMaps {
private Maps() {
throw new Error();
}
public static <K, MK, MV> Map<MK, MV> get(
Map<K, Map<MK, MV>> map, K key
) {
Map<MK, MV> nested = map.get(key);
if (nested == null) {
nested = new java.util.HashMap<MK, MV>();
map.put(key, nested);
}
return nested;
}
}
Perhaps better would be to write your own Map-like types to create on
demand.
Another approach is to use a single map with composite key. That also
may be faster and more memory efficient.
Tom Hawtin