英文:
How to reduce stream to single value if it size is 1 or to a default value if size > 1
问题
我有一个包含 0 到 n 个值的流。我想要:
- 如果流的
count()
为1
,则返回流中的值 - 如果流的
count()
为0
或>1
,则返回defaultValue
我开发的代码解决了这个问题:
String result = Stream.of("someValue")
.map(Optional::of) // reduce 不接受 `null`
.reduce((a, b) -> Optional.empty()) // 使用 `Optional.empty()` 替代 `null`
.flatMap(Function.identity()) // 解包 `Optional`
.orElseGet(() -> "defaultValue"); // 如果返回的 optional 为空,
// 则返回默认值
System.out.println(result);
但是将流值包装到 Optional
中的这种方法(在我看来)不易理解。
您是否了解基于流 API 的其他解决方案?如何以易于阅读的方式编写这段代码?
英文:
I have a stream with 0..n values. I want to:
- return value from stream if stream
count()
is1
- return
defaultValue
if streamcount()
is0
or> 1
Code what I developed resolved this problem:
String result = Stream.of("someValue")
.map(Optional::of) // reduce desn't accept `null`
.reduce((a, b) -> Optional.empty()) // instead `null`
.flatMap(Function.identity()) // unpack `Optional`
.orElseGet(() -> "defaultValue"); // if returned our optional is empty,
// so we can return default value
System.out.println(result);
But this hack with wraping stream values into Optional
isn't easy to understand (in my opinion).
Do you know any other solution, which bases on stream API? How to write this in easy to read way?
答案1
得分: 4
我不认为你需要将元素包装成可选项。你可以这样做:
yourStream.limit(2).reduce((x, y) -> defaultValue).orElse(defaultValue)
limit(2)
以便你不会消耗整个流。你只需要检查最多2个元素。
英文:
I don't think you need to wrap elements into optionals at all? You can just do:
yourStream.limit(2).reduce((x, y) -> defaultValue).orElse(defaultValue)
limit(2)
, so that you don't consume the whole stream. You just need to check at most 2 elements.
答案2
得分: 1
如果您想要更复杂的解决方案,可以使用以下代码:
<T> T exactlyOneOr(Stream<T> stream, T defaultValue) {
List<T> reference = new ArrayList<>(1);
boolean exactlyOne = spliterator.tryAdvance(reference::add)
&& !spliterator.tryAdvance(x -> {});
return exactlyOne ? reference.get(0) : defaultValue;
}
这仍然具有良好的性能,您不应该在理解上遇到太多麻烦。如果有疑问,随时要求进行澄清。
英文:
If you want a more complex solution, use the following:
<T> T exactlyOneOr(Stream<T> stream, T defaultValue) {
List<T> reference = new ArrayList<>(1);
boolean exactlyOne = spliterator.tryAdvance(reference::add)
&& !spliterator.tryAdvance(x -> {});
return exactlyOne ? reference.get(0) : defaultValue;
}
It is still performant and you shouldn't have much trouble understanding it. If you do, just ask for clarifications.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论