Получение двух разных выходов из потока
Я тестирую новый Stream
API в java-8 и хочу проверить результат 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
Я понимаю, почему это происходит, но как я могу напечатать счетчик для голов и хвостов, если я могу использовать поток только один раз?
Ответы
Ответ 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}
Ответ 2
Хотя все остальные ответы верны, они сформулированы немного громоздкими.
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>
становится a Long
, что приводит к a Map<Integer, Long>
.
Ответ 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]);