【问题标题】:How to stream a map with collection using Java 8 streams?如何使用 Java 8 流使用集合流式传输地图?
【发布时间】:2018-09-16 18:07:10
【问题描述】:

我想使用 Java 8 流传输带有集合的地图。

例如,有以下数据:

Map<String, Collection<Integer>> data;

我想用相应的键字符串来处理处理每个整数值的元素。例如:

data.keyValueStream((k,v)-> ...)

知道如何实现这一目标吗?谢谢。

* 关于“你为什么需要它?”这个问题,可能有很多原因,我不确定它是否重要。无论如何,我会和你一起“流动”......我的具体情况是批量插入数据库中的所有值,在它们的特定键下。让我们把它作为一个通用的 Java 8 流问题...

【问题讨论】:

  • 正确的解决方案可能取决于您真正想要实现的目标。你能解释一下你需要这些对吗?
  • data.forEach((key1, value1) -&gt; value1.forEach(item -&gt; { System.out.println("Key:" + key1 + " value: " + item); }));
  • 最简单和最有效的解决方案就是使用嵌套增强的 for 循环恕我直言。
  • 过去 14 小时忙于其他事情并投了 9 票?但至少有 4 票赞成 :) 很好奇... 为什么反对票?
  • 为“为什么需要这对?”的问题添加了解释

标签: java dictionary java-8 java-stream multimap


【解决方案1】:

您可以将您的Map&lt;String, Collection&lt;Integer&gt;&gt; 映射到List&lt;Map.Entry&lt;String, Integer&gt;&gt;

data.entrySet().stream()
  .flatMap(e -> e.getValue().stream().map(v -> new HashMap.SimpleEntry<>(e.getKey(), v)))
  .forEach(e -> System.out.printf("key %s val %d%n", e.getKey(), e.getValue()));

或:

data.forEach((k, v) -> v.forEach(n -> System.out.printf("key %s val %d%n", k, n)));

【讨论】:

  • 为什么用println(String.format("key %s, value %d",而不是更短的printf("key %s, value %d%n",
  • @Andreas 除此之外,flatMap 渴望直到 java-10,所以如果 OP 想要短路他不能;不像普通的循环
  • @Andreas 表示两个嵌套的forEach,使用printf 是更简单的选择。对于使用flatMap 的流,使用String.format 而不是new HashMap.SimpleEntry&lt;&gt;(…) 会更有意义(顺便说一句,这是一种伪装,因为嵌套类实际上是从AbstractMap 继承的,并且与@987654334 无关@)。 IE。 data.entrySet().stream() .flatMap(e -&gt; e.getValue().stream().map(v -&gt; String.format("key %s val %d%n", e.getKey(), v))) .forEach(System.out::print);
【解决方案2】:

我知道您在询问流版本,但如果您不打算使用并行性,最简单且可能更有效的选择是使用嵌套循环。这样,您可以避免花费时间和空间为每个 &lt;Key,CollectionItem&gt; 对创建临时实例。

你可以使用

for (Map.Entry<String, Collection<Integer>> entry : map.entrySet()){
    String key = entry.getKey();
    for (Integer number : entry.getValye()){
        //here we have access to <key, number> pair, 
        //handle them as you wish;
    }
}

【讨论】:

  • 但是,但是... 流是新的,所以它们肯定比循环更好! (我有时会绝望,因为人们忘记了旧的可以更好)。
  • @AndyTurner 一旦代码足够热,差异就会很小。我已经通过适当的 JMH 测试回答了此类问题
【解决方案3】:

虽然这可能有点明显,但您也可以这样写:

map.forEach((k, v) -> v.forEach(s -> System.out.println(k + "  " + s)))

例如,在 Java 9 中。

Map< String , Collection< Integer > > map =
    Map.ofEntries(
        Map.entry( "alpha" , List.of( 1 , 2 , 3 ) ) ,
        Map.entry( "beta" , List.of( 4 , 5 , 6 ) ) ,
        Map.entry( "gamma" , List.of( 7 , 8 , 9 ) )
    )
;

map.forEach( ( k , v ) -> {
        v.forEach( s -> System.out.println( k + "  " + s ) );
    }
);

【讨论】:

  • 你不需要ofEntries 来获取这么短的地图。您可以使用Map.of("alpha", List.of(1, 2, 3), "beta", List.of(4, 5, 6), "gamma", List.of(7, 8, 9))。此外,嵌套的forEach 不需要语句语法。所以你可以使用map.forEach((k, v) -&gt; v.forEach(s -&gt; System.out.println(k + " " + s)));
【解决方案4】:

流式处理仅处理单个值,因此您无法获得keyValueStream((k,v)-&gt; ...),但您可以获得keyValueStream(x -&gt; ...),其中x 是一个元组/对。

由于您从 Map 开始,它可以流式传输 Entry 对象(键/值对),并且您希望 lambda 中的键/值对,所以 Entry 对象流似乎合适。

这意味着您只想展平嵌套集合,例如像这样:

import java.util.AbstractMap.SimpleEntry;
data.entrySet()
    .stream()
    .flatMap(e -> e.getValue().stream().map(v -> new SimpleEntry<>(e.getKey(), v)))
    // At this point you have a Stream<Entry<String, Integer>> so you can e.g. do this:
    .forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()))
;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 2010-10-14
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多