2016-03-02 11 views
7

C'è un modo per sbirciare il prossimo elemento in un flusso? L'idea è passata da un flusso di un elenco di oggetti, in cui è necessario confrontare due oggetti seguenti (per semplificare alcune differenze, ma ciò non dovrebbe importare qui). Come un vecchio for ciclo sarebbe così:Sbircia il prossimo elemento in un flusso

List<Car> autobahn = getCars(); 
for (int i = 0; i < autobahn.size()-1; i++) { 
    if(autobahn.get(i).speed>autobahn.get(i+1).speed) 
     autobahn.get(i).honk(); 
} 

Il modo migliore per quanto flusso potrebbe essere:

autobahn.stream() 
      .limit(autobahn.size()-1) 
      .filter(car -> car.speed < autobahn.get(autobahn.indexOf(car)+1).speed) 
      .forEach(car -> car.honk()); 

Il principale problema di questa soluzione è il metodo indexOf, dal momento che ci potrebbe essere due volte la stessa auto sull'autostrada. Una soluzione migliore sarebbe un modo per sbirciare successivo (o quello prima) elemento (con una classe di aiutare, questo potrebbe essere ancora possibile, ma sembra orribile)

BoxedCar boxedCar = new BoxedCar(autobahn.get(0)); 
autobahn.stream() 
      .skip(1) 
      .filter(car -> boxedCar.setContent(car)) 
      .forEach(car -> car.winTheRace()); 

con helperclass

class BoxedCar { 

    Car content; 

    BoxedCar(Car content) { 
     this.content = content; 
    } 
    boolean setContent(Car content) { 
     double speed = this.content.speed; 
     this.content = content; 
     return content.speed > speed; 
    } 
} 

o per deviare il Stream<Car> in un tipo di Stream<(Car,Car)> con il secondo flusso in qualche modo creato dal primo (questo suona anche terribile e qui non ho idea, come questo sembrerebbe).

C'è un bel modo per farlo con i flussi, o siamo attaccati allo for -loop?

+3

Il ciclo for non è affatto ridicolo. In realtà, questo è probabilmente il codice più pulito che potrai scrivere per questo. È sempre possibile utilizzare un flusso sugli indici, ma questo è tutto. – Tunaki

+0

@Tunaki ho detto, i flussi sarebbero ridicoli, non il ciclo. Fino ad ora ho continuato con il ciclo for per ovvi motivi. Mi sto solo chiedendo se c'è una buona possibilità di ottenere questo anche con i flussi. Modifica, puoi capire quella parte sbagliata, la cancello. – ctst

+0

Ah ho frainteso scusa. – Tunaki

risposta

3

Attaccare con il ciclo for non sarebbe una cattiva idea. L'API Stream non è progettata per questo tipo di requisito. È possibile fare riferimento a that answer per ulteriori informazioni.

Tuttavia, un modo semplice per farlo utilizzando l'API Stream è quello di utilizzare un flusso sugli indici del proprio elenco, supponendo che si disponga dell'accesso casuale.

IntStream.range(0, autobahn.size() - 1) 
     .filter(i -> autobahn.get(i).speed > autobahn.get(i+1).speed) 
     .forEach(i -> autobahn.get(i).honk()); 

Si noti che questo altamente assomigliare il ciclo for.

+2

Assomiglia al ciclo 'for' ma rende possibile l'elaborazione parallela. –

+0

Come menzionato @ ErickG.Hagstrom, questo potrebbe avere prestazioni migliori. In qualche modo ho appena supervisionato questa soluzione elegante e semplice.Anche il link ha alcune risposte interessanti a questo aspetto. Non sono sicuro, se questa risposta è effettivamente più veloce nel mio caso d'uso (LinkedList), ma soddisfa definitivamente la mia domanda. – ctst

+1

@ctst Se hai un 'LinkedList', questa non è sicuramente la buona risposta, dal punto di vista delle prestazioni. Un LinkedList non ha accesso casuale, quindi l'accesso per indice è disastroso. In tal caso, sarebbe meglio prima convertire in un 'ArrayList', o usare un ciclo for con un iteratore. – Tunaki

0

cosa sull'utilizzo di un IntStream invece di un ciclo:

IntStream.range(0, autobahn.size() - 1) 
     .filter(i -> autobahn.get(i).speed < autobahn.get(i + 1).speed) 
     .forEach(i -> autobahn.get(i).honk()); 
1

Usando il mio libero StreamEx libreria:

StreamEx.of(autobahn) 
     .pairMap((car, nextCar) -> car.speed < nextCar.speed ? car : null) 
     .nonNull() 
     .forEach(Car::honk); 

Qui funzionamento non standard pairMap viene utilizzato, che può mappare la coppia adiacente di elementi al singolo elemento. Questo funziona per qualsiasi sorgente di streaming (non solo per l'elenco indicizzato ad accesso casuale) e può essere abbastanza ben bilanciata.

Problemi correlati