Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String manipulation in Java 8 Streams

I have a stream of Strings like- Token1:Token2:Token3 Here ':' is delimiter character. Here Token3 String may contain delimiter character in it or may be absent. We have to convert this stream into map with Token1 as key and value is array of two strings- array[0] = Token2 and array[1] = Token3 if Token3 is present, else null. I have tried something like-

return Arrays.stream(inputArray)
            .map( elem -> elem.split(":"))
            .filter( elem -> elem.length==2 )
            .collect(Collectors.toMap( e-> e[0], e -> {e[1],e[2]}));

But It didn't work. Beside that it do not handle the case if Token3 is absent or contain delimiter character in it.

How can I accomplish it in Java8 lambda expressions?

like image 921
Abhijeet srivastava Avatar asked Feb 07 '23 12:02

Abhijeet srivastava


1 Answers

You can map every input string to the regex Matcher, then leave only those which actually match and collect via toMap collector using Matcher.group() method:

Map<String, String[]> map = Arrays.stream(inputArray)
    .map(Pattern.compile("([^:]++):([^:]++):?(.+)?")::matcher)
    .filter(Matcher::matches)
    .collect(Collectors.toMap(m -> m.group(1), m -> new String[] {m.group(2), m.group(3)}));

Full test:

String[] inputArray = {"Token1:Token2:Token3:other",
        "foo:bar:baz:qux", "test:test"};
Map<String, String[]> map = Arrays.stream(inputArray)
    .map(Pattern.compile("([^:]++):([^:]++):?(.+)?")::matcher)
    .filter(Matcher::matches)
    .collect(Collectors.toMap(m -> m.group(1), m -> new String[] {m.group(2), m.group(3)}));
map.forEach((k, v) -> {
    System.out.println(k+" => "+Arrays.toString(v));
});

Output:

test => [test, null]
foo => [bar, baz:qux]
Token1 => [Token2, Token3:other]

The same problem could be solved with String.split as well. You just need to use two-arg split version and specify how many parts at most do you want to have:

Map<String, String[]> map = Arrays.stream(inputArray)
    .map(elem -> elem.split(":", 3)) // 3 means that no more than 3 parts are necessary
    .filter(elem -> elem.length >= 2)
    .collect(Collectors.toMap(m -> m[0], 
                              m -> new String[] {m[1], m.length > 2 ? m[2] : null}));

The result is the same.

like image 59
Tagir Valeev Avatar answered Feb 13 '23 22:02

Tagir Valeev