当前位置: 首页 > 知识库问答 >
问题:

如何在流中使用Map.computeIfAbsend()?

艾才良
2023-03-14

我有一个有趣的拼图游戏。假设我有一个字符串值列表:

["A", "B", "C"]

然后我必须在另一个系统中查询地图

{name="Annie", key="A"} -> 23
{name="Paul", key="C"} -> 16

我需要返回一个新的列表

 {key="A", count=23},
 {key="B", count=0},
 {key="C", count=16}

但是当我的一个User对象在地图中没有相应的count时,我很难进行计算。

我知道那张地图。computeIfAbsent()可以满足我的需要,但是如何根据原始列表的内容应用它呢?

我想我需要在原始列表上进行流式处理,然后应用compute?所以我有:

valuesList.stream()
 .map(it -> valuesMap.computeIfAbsent(it.getKey(), k-> OL))
 ...

但这就是我被卡住的地方。有人能提供一些关于我如何完成我需要的东西的见解吗?


共有2个答案

西门正平
2023-03-14
// First, map keys to users (assuming keys are unique for each user) ...
final Map<String,User> keyToUserMap = valuesMap.keySet().stream()
    .collect(Collectors.toMap(u -> u.key, u -> u));
        
Map<String,Long> map2 = valuesList.stream()
   .map(key -> {
     // Form a pair of (key, count)
     final User user = keyToUserMap.get(key);
     return new Object[] { 
        key, 
        user == null? 0L : valuesMap.get(user).count };
   })
  .collect(Collectors.toMap(pair -> (String) pair[0], pair -> (Long) pair[1]));
宗政浩慨
2023-03-14

您可以创建一个辅助映射

示例:

public record User(String name, String key) {}
public record UserCount(String key, long count) {}

public static void main(String[] args) {
    List<String> keys = List.of("A", "B", "C");
    
    Map<User, Long> countByUser =
        Map.of(new User("Annie", "A"), 23L,
               new User("Paul", "C"), 16L));
    
    Map<String, Long> countByKey = countByUser.entrySet().stream()
        .collect(Collectors.groupingBy(entry -> entry.getKey().key(), 
            Collectors.summingLong(Map.Entry::getValue)));

    List<UserCount> userCounts = keys.stream()
        .map(key -> new UserCount(key, countByKey.getOrDefault(key, 0L)))
        .collect(Collectors.toList());

    System.out.println(userCounts);
}

输出

[UserCount[key=A, count=23], UserCount[key=B, count=0], UserCount[key=C, count=16]]

关于将computeIfAbsent()用于流的想法,这种方法是错误的,流API的文档不鼓励这种方法。

当然,您可以使用computeIfAbsent()来解决这个问题,但不能与streams结合使用。创建一个通过副作用运行的流不是一个好主意(至少没有令人信服的理由)。

我猜你甚至不需要Java8computeIfAbsent(),简单明了的putIfAbsent()就足够了。

以下代码将产生相同的结果:

Map<String, Long> countByKey = new HashMap<>();

countByUser.forEach((k, v) -> countByKey.merge(k.key(), v, Long::sum));
keys.forEach(k -> countByKey.putIfAbsent(k, 0L));

List<UserCount> userCounts = keys.stream()
            .map(key -> new UserCount(key, countByKey.getOrDefault(key, 0L)))
            .collect(Collectors.toList());

如果这个选项看起来很复杂,你可以为循环创建两个增强的,而不是在地图和列表上应用forEach()

 类似资料:
  • 2)谁能建议如何使用x265enc元素将此管道改为h265格式广播?

  • 我的问题是,我有一个未知的组数,如果mapAsync的并行数少于我得到的组数,并且在最后一个接收器中出错 由于上游错误(Akka.Stream.Impl.StreamSubscriptionTimeoutSupport$$Anon$2),正在拆除SynchronousFileSink(/users/sam/dev/projects/akka-streams/target/log-error.txt

  • 问题内容: 给定一个Person上具有(etc)方法的where,我该如何将其转换为通过调用获得的where ? 我会使用Java 8之前的版本 但我想使用流和lambda做到这一点。 我看不到如何以功能样式执行此操作:Map / HashMap不实现。 返回可以流式传输的,但是如何向目的地地图添加新的内容? 问题答案: 使用Java 8,您可以执行以下操作: 尽管使用Guava的Maps.tra

  • 问题内容: 示例了如何使用内置的加密库和流来计算文件的md5。 但是是否可以将其转换为使用ES8异步/等待而不是使用上述回调,但仍保持使用流的效率? 问题答案: / 仅适用于promise,不适用于流。有一些想法可以制作一种类似流的额外数据类型,该数据类型将具有自己的语法,但是如果有的话,这些想法是高度实验性的,我将不赘述。 无论如何,您的回调仅等待流结束,这非常适合兑现承诺。您只需要包装流: 现

  • 我想从React客户端向服务器发送文件。我知道为此,我应该使用grpc流媒体并将文件分割成块。所以,问题是如何将这些块发送到服务器?

  • 我想利用一个简单的流从http服务收集一些额外的数据,并用这些结果来增强我的数据对象。下面说明了这一想法: 我有一个问题,要理解流的本质和流内部的物化/未来之间的机制和区别。 以下想法并没有向我解释: null