2014-05-16 10 views
6

Sto testando il nuovo StreamAPI in java-8 e voglio controllare il risultato di 10000 coinflip casuali. Finora ho:Come ottenere due uscite diverse da un flusso

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

ma questo genera l'eccezione:

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

capisco perché questo sta happenning ma come posso stampare il conteggio per le teste e le code, se posso usare solo il flusso una volta ?

+1

Penso che questo problema sia risolto (e si spera risolto) su questa discussione http://stackoverflow.com/questions/19803058/java-8-stream-getting-head-and-tail – luanjot

risposta

6

Questa prima soluzione si basa sul fatto che il conteggio del numero di teste e di code di 10 000 coinflip segue una legge binomiale.

Per questo caso d'uso particolare, è possibile utilizzare il metodo 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())); 


altrimenti si può utilizzare l'operazione collect di creare una mappa che mapperà ogni possibile risultato con il suo numero di occorrenze nel flusso.

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} 

Il vantaggio della soluzione ultima è che questo funziona per qualsiasi limiti dati per i numeri interi casuali che si desidera generare.

Esempio:

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

potrei chiedere l'unione è quale metodo ? –

1

È possibile raccogliere diversi risultati in una singola iterazione, se si desidera ottenere due uscite. Nel tuo caso, potrebbe apparire come segue:

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

Mentre tutte le altre risposte sono corrette, essi sono formulati un po 'ingombrante.

Map<Integer, Long>, mappa la moneta capovolta su un conteggio.

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

Ciò innanzitutto creare la IntStream, poi loro casella a un Stream<Integer>, come si sarà loro memorizzazione nella loro versione in scatola in ogni caso in questo esempio. E infine raccoglierli con una funzione groupingBy sull'identità i -> i, che vi dà una Map<Integer, List<Integer>>, che non è quello che volete, quindi si sostituisce il List<Integer> all'operazione Collectors.counting() su di esso, in modo che il List<Integer> diventa un Long, quindi con un conseguente Map<Integer, Long>.

+1

+1 Anche questa è una bella soluzione :-) –

Problemi correlati