I have been trying to figure out a solution for a while now, but I can't seem to get any suitable answer after thinking through/surfing the net for a solution. Hope the community can help me out!
I have some string and wishes to convert them into a nested map object, example below.
Fruits.Apple.Red
Fruits.Apple.Green
Fruits.Orange.Yellow
Fruits.Watermelon.Yellow
Fruits.Watermelon.Red
I would like to convert the above example into something like this.
{ Fruits:{
Apple:{
Red: null,
Green: null
},
Orange:{
Yellow: null
},
Watermelon:{enter code here
Yellow: null,
Red: null
}
}
}
Pardon me if you find this example to be a bad one. There is a reason why the value for the last child is null, I am trying to reproduce the problem I am facing.
CodePudding user response:
- Convert strings to map
- Split strings to arrays (String.split(".") function)
- Convert arrays to Map<String,Map<String,Object>:
arrays: ["Fruits","Apple","Red"], ["Fruits","Apple","Green"], ... ->
map: {"Fruits":{"Apple":{"Red":null},{"Green":null}},"Orange":{...},...}}
- Convert map to json using Gson (https://github.com/google/gson) or Jackson
Gson gson = new Gson();
return gson.toJson(map);
CodePudding user response:
A recursive function addToMap
may be implemented to find the key before the dot .
as a delimiter, creating a map if necessary using Map::computeIfAbsent
, or adding the key with null
value to the top-level map:
@SuppressWarnings({"rawtypes", "unchecked"})
static void addToMap(String s, Map<String, Map> upperLevel) {
int dotPos = s.indexOf(".");
if (dotPos < 0) {
upperLevel.put(s, null);
} else {
String key = s.substring(0, dotPos);
addToMap(s.substring(dotPos 1), upperLevel.computeIfAbsent(key, k -> new HashMap<>()));
}
}
Then the test may look as follows:
String[] arr = {
"Fruits.Cherry",
"Fruits.Apple.Red",
"Fruits.Apple.Green",
"Fruits.Orange.Yellow",
"Fruits.Watermelon.Yellow",
"Fruits.Watermelon.Red",
};
Map<String, Map> result = new HashMap<>();
for (String t : arr) {
addToMap(t, result);
}
System.out.println(result);
Output:
{Fruits={Apple={Red=null, Green=null}, Cherry=null, Watermelon={Red=null, Yellow=null}, Orange={Yellow=null}}}
If an insertion order is important, LinkedHashMap
should be created instead of HashMap
or an overridden version with Supplier<Map>
may be used:
Supplier<Map> mapSupplier = LinkedHashMap::new;
Map<String, Map> result = mapSupplier.get();
for (String t : arr) {
addToMap(t, result, mapSupplier);
}
System.out.println(result);
@SuppressWarnings({"rawtypes", "unchecked"})
static void addToMap(String s, Map<String, Map> upperLevel, Supplier<Map> mapSupplier) {
int dotPos = s.indexOf(".");
if (dotPos < 0) {
upperLevel.put(s, null);
} else {
String key = s.substring(0, dotPos);
addToMap(s.substring(dotPos 1), upperLevel.computeIfAbsent(key, k -> mapSupplier.get()), mapSupplier);
}
}
Output (order changed):
{Fruits={Cherry=null, Apple={Red=null, Green=null}, Orange={Yellow=null}, Watermelon={Yellow=null, Red=null}}}