freedev
freedev

Reputation: 30037

java8 reduce with useless combiner

I need to apply a list of regex to a string, so I thought to use java8 map reduce:

List<SimpleEntry<String, String>> list = new ArrayList<>();

list.add(new SimpleEntry<>("\\s*\\bper\\s+.*$", ""));
list.add(new SimpleEntry<>("\\s*\\bda\\s+.*$", ""));
list.add(new SimpleEntry<>("\\s*\\bcon\\s+.*$", ""));

String s = "Tavolo da cucina";

String reduced = list.stream()
    .reduce(s, (v, entry) -> v.replaceAll(entry.getKey(), entry.getValue()) , (c, d) -> c);

Actually this code may be is not very beautiful, but it works. I know this cannot be parallelised and for me is ok.

Now my question is: is there any chance with Java8 (or higher version) to write something more elegant? I mean also avoiding to add the useless combiner function.

Upvotes: 0

Views: 232

Answers (2)

freedev
freedev

Reputation: 30037

Inspired by Oleksandr's comment and Holger I wrote this

String reduced = list.stream()
.map(entry-> 
    (Function<String, String>) v -> v.replaceAll(entry.getKey(), entry.getValue()))
.reduce(Function.identity(), Function::andThen)
.apply(s);

This also reduce all entries to a function composition.

Upvotes: 2

ernest_k
ernest_k

Reputation: 45309

Here's another, interesting approach: reduce all entries to a function composition, then apply that composed function on the original input:

String result = list.stream()
        .map(entry -> 
            (Function<String, String>) text -> 
                       text.replaceAll(entry.getKey(), entry.getValue()))
        //following op also be written as .reduce(Function::compose) (see comment by Eugene)
        .reduce((f1, f2) -> f1.andThen(f2)) //compose functions
        .map(func -> func.apply(s)) //this basically runs all `replaceAll`
        .get();

The result of this is your expected string. While this function composition is not intuitive, it nonetheless seems to fit the idea that your original list is in fact a sort of "transformation logic" chain.

Upvotes: 1

Related Questions