Reputation: 197
I am trying to write a java program to iterate over a multi-level hashmap. For example, I have
a HashMap <String, Object>
, where Object can be another HashMap<String, Object>
.
The level of this hashmap can be n (>5).
Can someone give me a hint on how to write it in java? Does java provide some utility?
Thanks
Upvotes: 5
Views: 7638
Reputation: 1066
// Depth first traversal where entry keys are represented as the list of keys to address the current element
static Stream<Map.Entry<List<String>, Object>> flatten(List<String> keys, Stream<Map.Entry<String, Object>> entries) {
return entries.flatMap(entry -> {
List<String> keysWithCurrentKey = Stream.concat(keys.stream(), Stream.of(entry.getKey())).collect(Collectors.toList());
if(entry.getValue() instanceof Map) {
Map<String, Object> map = (Map<String, Object>) entry.getValue();
return flatten(
keysWithCurrentKey,
map.entrySet().stream()
);
} else {
return Stream.of(Map.entry(keysWithCurrentKey, entry.getValue()));
}
});
}
static Stream<Map.Entry<List<String>, Object>> flatten(Stream<Map.Entry<String, Object>> entries) {
return flatten(List.of(), entries);
}
e.g
Map<String, Object> map = Map.of(
"a", "b",
"c", "d",
"e", Map.of("f", Map.of("g", "h"))
);
flatten(map.entrySet().stream())
.forEach(flattenedEntry -> {
System.out.println(flattenedEntry);
});
produces
[e, f, g]=h
[a]=b
[c]=d
Upvotes: 0
Reputation: 303
When you have n level depth it is better to use recursion, I have faced the same problem where my map depth level is > 3. Below is the solution which work for me.
private void mapIterator(Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Map) {
mapIterator((Map<String, Object>) entry.getValue());
} else {
//your logic goes here.
System.out.println(entry.getKey()+" : "+ entry.getValue());
}
}
}
Upvotes: 1
Reputation: 3151
I don't mean to steal @David Frank's thunder. On the opposite, I'm giving him all the credit. Here is a slight modification over his code where you would get a flat output map with a dot-separated keySet
:
public void iterate(String currentKey, Map<String, Object> map, Map<String, String> out) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Map) {
iterate(currentKey + "." + entry.getKey(), (Map<String, Object>) entry.getValue(), out);
} else {
out.put(currentKey + "." + entry.getKey(), entry.getValue().toString());
}
}
}
To keep it as simple as possible, I'm not removing the .
at the beginning of each key.
Upvotes: 0
Reputation: 346
Without knowing anything about the nature of your program, here is a generic example of recursion with a hashmap:
public void printAll(HashMap<String, Object> map) {
for (Object o : map.values()) {
if (o instanceof HashMap) {
printAll((HashMap<String, Object>) o);
} else {
System.out.println(o.toString());
}
}
}
May not be 100% correct syntax, just typing from memory.
Upvotes: 2
Reputation: 6092
public void iterate(Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.println("Key is: " + entry.getKey());
if (entry.getValue() instanceof Map) {
System.out.println("Map found, digging further");
iterate((Map<String, Object>) entry.getValue());
} else {
System.out.println("Leaf found, value is: " + entry.getValue());
}
}
}
This does a depth-first iteration. However, since java is a strongly typed language, nesting hashmaps and other types is generally not a good idea. Most of the time there are solutions which do not involve such hacking.
Upvotes: 5
Reputation: 2221
You can start by checking whether the type of object
is a HashMap
and then check its length
whether it has more contents or not.
Upvotes: 0