How to use Java regex or Java streams for the give

2019-07-22 14:31发布

问题:

I have a string with the following pattern,

String test = "name=ravi,age=30,id=1;name=teja,age=32,id=2";

As you can see above, ";" is used to separate persons and "," is used to separate person's attributes and "=" to map the values of those attributes.

I would like to convert the above string into a Map<String, Map<String, String>> where the key for the outer map is the id and the key for the inner map is the name.

Given that it is always guaranteed to have unique ids and names across the string, how do I achieve the requirement using Java regex or Java streams?

I could have done this using StringTokenizer or "split" method, but I would like to see if there is any other better way of doing this.

Edit: I have reached this far till now

List<String> persons =
                Arrays.asList(test.split(";"));

        List<List<String>> personAttribs =
                persons.stream().map(s -> Arrays.asList(s.split(","))).collect(Collectors.toList());

I am unable to take the personAttribs and convert that to the map I am looking for.

回答1:

Absolutely just for fun:

    Pattern p2 = Pattern.compile(",");
    Pattern p3 = Pattern.compile("=");
    String[] tokens = test.split(";");

    for (String token : tokens) {
        List<String> list = p2.splitAsStream(token)
                .flatMap(x -> p3.splitAsStream(x))
                .collect(Collectors.toList());

        result.put(list.get(5), IntStream.of(0, 2)
                .boxed()
                .collect(Collectors.toMap(list::get, x -> list.get(x + 1))));
    }

    System.out.println(result); // {1={name=ravi, age=30}, 2={name=teja, age=32}}

With java-9 this could be even nicer:

    Pattern p = Pattern.compile(";");
    Pattern p2 = Pattern.compile(",");
    Pattern p3 = Pattern.compile("=");

    List<String> list = p.splitAsStream(test)
            .flatMap(p2::splitAsStream)
            .flatMap(p3::splitAsStream)
            .collect(Collectors.toList());

    Map<String, Map<String, String>> result = IntStream.iterate(5, x -> x + 6)
            .limit(list.size() / 6)
            .boxed()
            .collect(Collectors.toMap(
                    list::get,
                    x -> Map.of(
                          list.get(x - 5), 
                          list.get(x - 4), 
                          list.get(x - 3), 
                          list.get(x - 2))));