使用 List<UnaryOperator<...>> 映射对象
Mapping an object using a List<UnaryOperator<...>>
我有一个 List<UnaryOperator<String>>
并且需要 map/transform 通过运算符列表传递一个字符串。我有以下功能 Java 11 代码:
UnaryOperator<String> addA = (startString) -> startString + "a";
UnaryOperator<String> addB = (startString) -> startString + "b";
UnaryOperator<String> addc = (startString) -> startString + "c";
List<UnaryOperator<String>> operators = List.of(addA, addB, addc);
String concatenatedString =
operators
.stream()
.reduce(
"", // identity
(value, op) -> op.apply(value), // accumulator
(value1, value2) -> value1.concat(value2) // combiner
);
System.out.println(concatenatedString); // prints "abc" as expected.
我担心的是字符串连接在 2 个地方表示。每个 UnaryOperator
中的第一个,组合器参数中的第二个。让我想知道是否有更好的方法来做到这一点?
您可以使用 andThen 将三个 UnaryOperator
组合成一个 Function
以形成转换管道。
Function<String, String> addABC = addA
.andThen(addB)
.andThen(addc);
System.out.println(addABC.apply("")); //Prints abc
如果您有多个 UnaryOperator
开始,请参阅 Nicholas 的回答,了解如何将它们减少到单个 UnaryOperator
。
reduce
方法使用组合器实现并行。在并行流中,reduce
可以一次 运行 许多一元运算符,并使用提供的组合器组合结果。 combiner
的存在是by-design,并没有过错
这段代码的问题不在于你在源代码中的两个地方表达了连接,而是你在 运行time 进行了很多次字符串连接,这造成了很多不必要的字符串。
您应该改用字符串生成器。由于 StringBuilder
是可变的,您不会创建很多 StringBuilder
(除非您使用并行流,但那是另一回事),并且您将使用 collect
,而不是reduce
。注意另一个从 UnaryOperator
到 Consumer
的变化:
Consumer<StringBuilder> addA = (startString) -> startString.append("a");
Consumer<StringBuilder> addB = (startString) -> startString.append("b");
Consumer<StringBuilder> addc = (startString) -> startString.append("c");
List<Consumer<StringBuilder>> operators = List.of(addA, addB, addc);
StringBuilder concatenatedString =
operators
.stream()
.collect(
StringBuilder::new, // identity
(value, op) -> op.accept(value), // accumulator
StringBuilder::append // combiner
);
System.out.println(concatenatedString);
我可以建议另一种使用二元运算符连接字符串的方法,但该建议不太可能成为您代码片段的优化。
String concatenatedString = operators
.stream().reduce((op1, op2) -> (val) -> op1.apply(val) + op2.apply(val))
.get().apply("");
您可以利用 UnaryUperator<T> extends Function<T, T>
的优势并链接 Function::andThen
的多个调用以获得列表中所有内容的组合 UnaryOperator<String>
:
UnaryOperator<String> mergedUnaryOperators = operators.stream()
.reduce((l, r) -> (string) -> l.andThen(r).apply(string))
.orElseGet(UnaryOperator::identity);
String output = mergedUnaryOperators.apply(""); // results in "abc"
为了更清楚地了解它是如何工作的,在 reduce
方法中调用它:
new BinaryOperator<UnaryOperator<String>>() {
@Override
public UnaryOperator<String> apply(UnaryOperator<String> l, UnaryOperator<String> r) {
return string -> l.andThen(r).apply(string);
}
}
这个解决方案怎么样:
Function<String, String> combineF = operators.stream()
.reduce(UnaryOperator.identity(), (l, r) -> (string) -> r.compose(l).apply(string));
System.out.println(combineF.apply(""));
我有一个 List<UnaryOperator<String>>
并且需要 map/transform 通过运算符列表传递一个字符串。我有以下功能 Java 11 代码:
UnaryOperator<String> addA = (startString) -> startString + "a";
UnaryOperator<String> addB = (startString) -> startString + "b";
UnaryOperator<String> addc = (startString) -> startString + "c";
List<UnaryOperator<String>> operators = List.of(addA, addB, addc);
String concatenatedString =
operators
.stream()
.reduce(
"", // identity
(value, op) -> op.apply(value), // accumulator
(value1, value2) -> value1.concat(value2) // combiner
);
System.out.println(concatenatedString); // prints "abc" as expected.
我担心的是字符串连接在 2 个地方表示。每个 UnaryOperator
中的第一个,组合器参数中的第二个。让我想知道是否有更好的方法来做到这一点?
您可以使用 andThen 将三个 UnaryOperator
组合成一个 Function
以形成转换管道。
Function<String, String> addABC = addA
.andThen(addB)
.andThen(addc);
System.out.println(addABC.apply("")); //Prints abc
如果您有多个 UnaryOperator
开始,请参阅 Nicholas 的回答,了解如何将它们减少到单个 UnaryOperator
。
reduce
方法使用组合器实现并行。在并行流中,reduce
可以一次 运行 许多一元运算符,并使用提供的组合器组合结果。 combiner
的存在是by-design,并没有过错
这段代码的问题不在于你在源代码中的两个地方表达了连接,而是你在 运行time 进行了很多次字符串连接,这造成了很多不必要的字符串。
您应该改用字符串生成器。由于 StringBuilder
是可变的,您不会创建很多 StringBuilder
(除非您使用并行流,但那是另一回事),并且您将使用 collect
,而不是reduce
。注意另一个从 UnaryOperator
到 Consumer
的变化:
Consumer<StringBuilder> addA = (startString) -> startString.append("a");
Consumer<StringBuilder> addB = (startString) -> startString.append("b");
Consumer<StringBuilder> addc = (startString) -> startString.append("c");
List<Consumer<StringBuilder>> operators = List.of(addA, addB, addc);
StringBuilder concatenatedString =
operators
.stream()
.collect(
StringBuilder::new, // identity
(value, op) -> op.accept(value), // accumulator
StringBuilder::append // combiner
);
System.out.println(concatenatedString);
我可以建议另一种使用二元运算符连接字符串的方法,但该建议不太可能成为您代码片段的优化。
String concatenatedString = operators
.stream().reduce((op1, op2) -> (val) -> op1.apply(val) + op2.apply(val))
.get().apply("");
您可以利用 UnaryUperator<T> extends Function<T, T>
的优势并链接 Function::andThen
的多个调用以获得列表中所有内容的组合 UnaryOperator<String>
:
UnaryOperator<String> mergedUnaryOperators = operators.stream()
.reduce((l, r) -> (string) -> l.andThen(r).apply(string))
.orElseGet(UnaryOperator::identity);
String output = mergedUnaryOperators.apply(""); // results in "abc"
为了更清楚地了解它是如何工作的,在 reduce
方法中调用它:
new BinaryOperator<UnaryOperator<String>>() {
@Override
public UnaryOperator<String> apply(UnaryOperator<String> l, UnaryOperator<String> r) {
return string -> l.andThen(r).apply(string);
}
}
这个解决方案怎么样:
Function<String, String> combineF = operators.stream()
.reduce(UnaryOperator.identity(), (l, r) -> (string) -> r.compose(l).apply(string));
System.out.println(combineF.apply(""));