2015-06-07 18 views
11

Voglio generare un elenco di numeri utilizzando espressioni lambda e non un ciclo for.Espressioni lambda in Java 8

Quindi diciamo che voglio generare un elenco di tutti i numeri triangolari sotto 100. numeri triangolari sono numeri che seguono la formula: (n * n + n)/2

Qual è il modo migliore di fare questo ? Attualmente ho questo:

Stream.iterate(1, n -> n + 1).limit(100) 
      .map(n -> (n * n + n)/2) 
      .filter(a -> a < 100) 
      .map(a -> a + "") 
      .collect(Collectors.joining(", ", "Numbers: ", ".")); 

ma questo sembra inutilmente eccessivo con la quantità di calcoli. Ripetere iterando da 1 a 100 (poiché supponiamo di non sapere quale sia il valore massimo per n), quindi mappo la funzione del numero triangolare di quell'elenco e poi controllo quali numeri hanno meno di 100. Esiste un modo più efficiente nel fare questo? Inoltre: posso generare i numeri dei triangoli usando solo la funzione iterate di Stream invece di usare iterate, limit e quindi mappare?

MODIFICA: Quindi il punto principale è: in che modo il calcolo dei numeri di coda può interrompersi non appena uno dei numeri del triangolo supera 100? solito avrei scritto così:

ArrayList<Integer> triangles = new ArrayList<>(); 
for (int n=1;true;n++) { 
    int num = (n*n+n)/2; 

    if (num>100) break; 

    triangles.add(num); 
} 

che ferma non appena un numero triangolo supera 100, che è molto efficiente; come posso mantenere questa efficienza nell'espressione lambda?

+2

'Stream.iterate (1, n-> n + 1) .limit (100)' può essere riscritto come 'IntStream.rangeClosed (1, 100)' che è probabilmente più leggibile. – Pshemo

+0

perché stai usando sia un limite che un filtro?Credo che il secondo filtro limiterà l'output in base al calcolo, quindi otterrete solo risultati inferiori a 100, anziché input inferiori a 100. –

+0

Qual è il punto? O è solo curiosità? – doublep

risposta

6

In generale, quello che stai cercando è take-while. Sfortunatamente, non ha implementazioni predefinite nei flussi Java 8. Vedere un question about take-while.

+3

Si sta lavorando per Java 9 però. –

-2

Se tutto quello che stai cercando di fare è convertire la sequenza data nel triangolo (come descrivi), questo è molto più semplice.

List<Integer> l = IntStream.rangeClosed(1, 100) 
      .mapToObj(n -> (n*n + n)/2) 
      .collect(Collectors.toList()); 

involucri flusso primitive bisogno di un ulteriore passaggio per up-convertire in oggetti, quindi il metodo mapToObj.

Se stai cercando di smettere di filtrare quando si colpisce 100, modo più semplice che posso pensare è

IntFunction<Integer> calc =n -> (n*n+n)/2; 
    List<Integer> l = IntStream.rangeClosed(1, 100) 
      .filter(n -> calc.apply(n) < 100) 
      .mapToObj(calc) 
      .collect(Collectors.toList()); 

Sulla base delle modifiche alla tua domanda, credo che questo è anche abbastanza importante sottolineare. Se si desidera eseguire il mirroring quello che hai utilizzato per fare, che sarebbe simile a questa:

List<Integer> results = new ArrayList<>(100); 
    IntStream.rangeClosed(1, 100).forEach(i -> { 
     int tri =calc.apply(i); 
     if(tri < 100) { 
      results.add(tri); 
     } 
    }); 

Vale la pena sottolineare che i flussi non sono necessariamente in ordine (anche se l'implementazione di default segue l'iteratore). Se questo fosse convertito in un flusso parallelo vedresti la differenza (e la potenza dei flussi). Non puoi interrompere l'esecuzione perché in questo caso stai assumendo una certa quantità sull'ordine di elaborazione. Filtrando in anticipo (nel mio secondo modulo) ti assicurerai di finire con un flusso di risultati di 13 voci prima del calcolo finale. Prendi questa opzione parallela come una nota.

List<Integer> l = IntStream.rangeClosed(1, 100).parallel() 
      .filter(n -> calc.apply(n) < 100) 
      .mapToObj(calc) 
      .collect(Collectors.toList()); 

Vedrete che sono ancora ordinati, ma il calcolo di questi è stato fatto su più thread.

+1

L'OP chiede come interrompere lo streaming quando il valore di '(n * n + n)/2' inizierà a diventare maggiore di 100, a causa del numero elevato di casi che dovranno essere filtrati. Quindi la domanda è "se sappiamo che i valori dopo un certo valore n-esimo non saranno necessari come possiamo saltarli". – Pshemo

+0

Op non ha ancora risposto a nessuna domanda. Non è chiaro cosa sta chiedendo ancora. –

+3

@JohnAment se non ti è chiaro quale sia la domanda, è un buon motivo per non rispondere. –