【问题标题】:Java8 sum up to a limit with streamsJava8 对流的总结达到了极限
【发布时间】:2016-11-12 15:02:27
【问题描述】:

我有这个 LinkedHashMap:

myMap = {
  0 => 10,
  1 => 6,
  2 => 28,
  ...
}
int limit = 15;

我想要使用流做的是求和(按顺序)地图值,并在达到限制时停止,并返回地图中的相关索引(在本例中为 0)。 流有优雅的方式吗?

【问题讨论】:

  • 我没有看到。总有办法做到这一点,但与简单的循环相比,它会被人为设计。 Justa 问题,为什么你使用 LinkedHashMap 而不是 List,因为你的键是索引?
  • @Andrea,java 8 没有takeWhile 操作来执行“达到限制时停止”
  • 在你的例子中应该返回什么,例如 5 和 100?
  • Maps 没有索引,它们有键。为什么要求“有流的优雅方式”,“没有流的优雅方式”有什么问题?

标签: hashmap java-8 java-stream


【解决方案1】:

你可以这样总结一个极限

myMap.values().reduce(0, (a, b) -> a+b > limit ? a : a + b);

【讨论】:

    【解决方案2】:

    可以通过我的免费 StreamEx 库来扩展标准 Stream API,尽管即使使用库也不是很优雅:

    EntryStream.of(myMap) // like myMap.entrySet().stream()
        .prefix(
           (e1, e2) -> new AbstractMap.SimpleEntry<>(e2.getKey(), e1.getValue() + e2.getValue()))
        .takeWhile(e -> e.getValue() < limit)
        .reduce((a, b) -> b)
        .ifPresent(System.out::println);
    

    这里我们使用了两个特殊的 StreamEx 操作。一种是prefix,它懒惰地计算运行前缀(如Haskell 中的scanl)。这里对于两个条目,我们选择后一个的键和它们的值的总和,创建一个新条目。接下来,我们使用takeWhile(也将出现在 Java 9 标准 Stream API 中)在 value 超过限制时立即停止。最后我们减少到最后找到的元素,如果它存在则打印它,所以我们不仅有索引,还打印了最终总和(如果你只需要索引,添加.map(Entry::getKey)步骤)。

    虽然这样的解决方案更像是 FP,但我一般不会推荐它,因为它效率不高并且会产生垃圾(中间条目和装箱整数),更不用说外部库依赖了。使用普通的旧 for 循环。它高效且易于理解:

    int sum = 0;
    Integer lastKey = null;
    for(Map.Entry<Integer, Integer> e : myMap.entrySet()) {
        sum+=e.getValue();
        if(sum >= limit) break;
        lastKey = e.getKey();
    }
    if(lastKey != null) {
        System.out.println(lastKey);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2015-05-12
      • 1970-01-01
      相关资源
      最近更新 更多