如何在流的大小为1时将其缩减为单个值,或在大小大于1时缩减为默认值。

huangapple go评论65阅读模式
英文:

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() is 1
  • return defaultValue if stream count() is 0 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:

&lt;T&gt; T exactlyOneOr(Stream&lt;T&gt; stream, T defaultValue) {
  List&lt;T&gt; reference = new ArrayList&lt;&gt;(1);
  boolean exactlyOne = spliterator.tryAdvance(reference::add)
      &amp;&amp; !spliterator.tryAdvance(x -&gt; {});
  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.

huangapple
  • 本文由 发表于 2020年9月15日 17:33:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/63899040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定