【问题标题】:Getting two different outputs from a Stream从 Stream 获取两个不同的输出
【发布时间】:2014-05-16 15:29:43
【问题描述】:

我正在 java-8 中测试新的 Stream API 并想检查 10000 次随机硬币翻转的结果。到目前为止,我有:

    public static void main(String[] args) {

        Random r = new Random();
        IntStream randomStream = r.ints(10000,0, 2);

        System.out.println("Heads: " + randomStream.filter(x -> x==1).count());
        System.out.println("Tails: " + randomStream.filter(x -> x==0).count());
    }

但这会引发异常:

 java.lang.IllegalStateException: stream has already been operated upon or closed

我明白为什么会发生这种情况,但是如果我只能使用一次流,我如何打印正面和反面的计数?

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

第一个解决方案依赖于这样一个事实,即计算 10 000 次硬币翻转的正面和反面数量遵循二项式定律。

对于这个特定的用例,您可以使用summaryStatistics 方法。

Random r = new Random();
IntStream randomStream = r.ints(10000,0, 2);
IntSummaryStatistics stats =  randomStream.summaryStatistics();
System.out.println("Heads: "+ stats.getSum());
System.out.println("Tails: "+(stats.getCount()-stats.getSum()));


否则,您可以使用collect 操作创建一个映射,该映射将映射每个可能的结果及其在流中的出现次数。
Map<Integer, Integer> map = randomStream
                            .collect(HashMap::new, 
                                     (m, key) -> m.merge(key, 1, Integer::sum), 
                                     Map::putAll);
System.out.println(map); //{0=4976, 1=5024}

最后一个解决方案的优点是,这适用于您为要生成的随机整数指定的任何范围。

例子:

IntStream randomStream = r.ints(10000,0, 5);
....
map => {0=1991, 1=1961, 2=2048, 3=1985, 4=2015}

【讨论】:

  • 请问merge是什么方法?
【解决方案2】:

虽然所有其他答案都是正确的,但它们的表述有点麻烦。

Map&lt;Integer, Long&gt;,将翻转的硬币映射到计数。

Map<Integer, Long> coinCount = new Random().ints(10000, 0, 2)
        .boxed()
        .collect(Collectors.groupingBy(i -> i, Collectors.counting()));

这将首先创建IntStream,然后将它们装箱到Stream&lt;Integer&gt;,因为在此示例中无论如何您都将它们存储在装箱版本中。最后,在身份i -&gt; i 上使用groupingBy 函数收集它们,这会为您提供Map&lt;Integer, List&lt;Integer&gt;&gt;,这不是您想要的,因此您将List&lt;Integer&gt; 替换为操作Collectors.counting(),这样List&lt;Integer&gt; 变为 Long,因此导致 Map&lt;Integer, Long&gt;

【讨论】:

    【解决方案3】:

    如果您想获得两个输出,您可以在一次迭代中收集多个结果。在您的情况下,它可能如下所示:

    Random r = new Random();
    IntStream randomStream = r.ints(10000,0, 2);
    
    int[] counts = randomStream.collect(
        () -> new int[] { 0, 0 }, // supplier
        (a, v) -> a[v]++, // accumulator
        (l, r) -> { l[0] += r[0]; l[1] += r[1]; }); // combiner
    
    System.out.println("Heads: " + counts[0]);
    System.out.println("Tails: " + counts[1]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多