从Stream获取两个不同的输出

时间:2014-05-16 15:29:44

标签: java java-8 java-stream

我正在测试java-8中的新Stream API,并希望检查10000随机coinflips的结果。到目前为止,我有:

    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

我理解为什么会发生这种情况,但如果我只能使用一次流,我该如何打印头尾的计数呢?

3 个答案:

答案 0 :(得分:6)

这第一个解决方案依赖于计算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}

答案 1 :(得分:4)

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

Map<Integer, Long>,将翻转的硬币映射到计数。

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

这将首先创建IntStream,然后将它们设置为Stream<Integer>,因为您将在此示例中将它们存储在其盒装版本中。最后使用身份groupingBy上的i -> i函数收集它们,这会为您提供Map<Integer, List<Integer>>,这不是您想要的,因此您将List<Integer>替换为操作其上Collectors.counting()List<Integer>变为Long,因此产生Map<Integer, Long>

答案 2 :(得分:1)

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

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]);