简体   繁体   中英

Converting delimited string/text into a map object

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.

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}}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM