2

I have few lines of code, which I'm trying to convert to functional paradigm. The code is:

private String test(List<String> strings, String input) {

    for (String s : strings) {
        input = input.replace(s, ", ");
    }

    return input;
}

I need to make this one instruction chain. It must replace all strings from given list with coma IN given String input. I tried to do it with map method, but with no success. I'm aware I can do it if I appended input string into list at beginning and call map then, but the list is immutable, so I cannot do that.

1
  • 2
    Why not use replaceAll with a regex based from strings? Like return input.replaceAll(String.join("|", strings), ", "); This may not have the same result depending on the strings though. Commented Feb 6, 2016 at 17:29

3 Answers 3

2

I believe you can do this with a simple reduce:

strings.stream().reduce(input, (in, s) -> in.replace(s, ", "));

It takes the input, and replaces each occurence of the first string with ", ". Then it takes that result, and uses it as the input along with the next string, and repeats for every item in the list.

As Louis Wasserman points out, this approach cannot be used with parallelStream, so it won't work if you want parallelization.

Sign up to request clarification or add additional context in comments.

2 Comments

Note that this won't work if you use parallelStream -- the input isn't actually an identity, and Bad Things will happen.
@Louis Wasserman: even worse, there’s actually no guaranty that the identity will be used when the stream is not empty, e.g. for a single element stream, returning the element would be a legal implementation, as identity op element is required to evaluate to element, so the implementation could just return element. Or return first op second for a two element stream…
1

The only think I can think of -- which is pretty awkward -- is

 strings.stream()
     .map(s -> (Function<String, String>) (x -> x.replace(s, ", ")))
     .reduce(Function.identity(), Function::andThen)
     .apply(input)

2 Comments

Wow, that is indeed a bit awkward, although congratulations, wouldn't think of that
Now that is functional programming. I'm both horrified and delighted.
0

The following does pretty much the same thing.

private String test(List<String> strings, String input) {
    return input.replaceAll(
            strings
                .stream()
                .map(Pattern::quote)
                .collect(Collectors.joining("|"))
            , ", "
    );
}

The main difference is that it first combines all the search strings into a single regex, and applies them all at once. Depending on size of your input strings, this may perform even better than your original use case.

If the list of strings is fixed, or changes only rarely, you can get some more speed from precompiling the joined pattern.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.