2014-05-16 23 views
6

Tôi đang thử nghiệm StreamAPI mới trong java-8 và muốn kiểm tra kết quả của 10000 coinflips ngẫu nhiên. Cho đến nay tôi có:Nhận hai kết quả đầu ra khác nhau từ Luồng

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()); 
    } 

nhưng điều này ném ngoại lệ:

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

Tôi hiểu tại sao điều này happenning nhưng làm thế nào tôi có thể in số lượng cho người đứng đầu và đuôi nếu tôi chỉ có thể sử dụng dòng một lần ?

+1

Tôi nghĩ rằng vấn đề này được giải quyết (và hy vọng được giải quyết) về chủ đề này http://stackoverflow.com/questions/19803058/java-8-stream-getting-head-and-tail – luanjot

Trả lời

6

Giải pháp đầu tiên này dựa trên thực tế là việc đếm số đầu và đuôi của 10 000 đồng xu tuân theo luật nhị thức.

Đối với trường hợp sử dụng cụ thể này, bạn có thể sử dụng phương thức 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())); 


Nếu không, bạn có thể sử dụng các hoạt động collect để tạo ra một bản đồ mà sẽ vạch mỗi kết quả có thể với số lượng các lần xuất hiện trong dòng.

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} 

Lợi thế của giải pháp cuối cùng là điều này phù hợp với bất kỳ giới hạn nào bạn đưa ra cho các số nguyên ngẫu nhiên mà bạn muốn tạo.

Ví dụ:

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

tôi có thể yêu cầu hợp nhất là phương pháp nào ? –

1

Bạn có thể thu thập nhiều kết quả trong một sự lặp lại duy nhất, nếu bạn muốn nhận được hai kết quả đầu ra. Trong trường hợp của bạn, nó có thể trông giống như sau:

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

Trong khi tất cả các câu trả lời khác là chính xác, chúng được xây dựng một chút cồng kềnh.

Map<Integer, Long>, ánh xạ đồng xu đã lật lên một số.

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

này đầu tiên sẽ tạo ra IntStream, sau đó hộp chúng vào một Stream<Integer>, vì bạn sẽ được lưu trữ chúng trong phiên bản đóng hộp của họ dù sao đi nữa trong ví dụ này. Và cuối cùng thu thập chúng với chức năng groupingBy trên danh tính i -> i, cung cấp cho bạn Map<Integer, List<Integer>>, không phải là thứ bạn muốn, do đó bạn thay thế List<Integer> bằng thao tác Collectors.counting() trên đó, sao cho List<Integer> trở thành Long, do đó dẫn đến Map<Integer, Long>.

+1

+1 Đây là một giải pháp tốt đẹp quá :-) –

Các vấn đề liên quan