2015-04-28 13 views
11

Sono nuovo per espressioni lambda e sto cercando di usarli per ridurre il codice seguente all'equivalente lambda. Ho esaminato riduci, flatMap e forEach, oltre a molte altre cose, ma ovviamente mi manca qualcosa perché tutto ciò che provo è sintatticamente sbagliato o non ho un riferimento per ciò di cui ho bisogno.Espressione lambda Java per cicli annidati con condizionale

Devo eseguire un'analisi di ciascun elemento rispetto a tutti gli altri elementi di una raccolta. L'ho codificato come loop annidato con un condizionale. Una volta identificati gli elementi non corrispondenti, viene eseguito un calcolo utilizzando entrambi gli elementi. Infine, voglio una raccolta di risultati per ogni calcolo comparativo.

Quindi, ecco il codice originale:

final List<Element> updated = new ArrayList<>(elements.size()); 

for (final Element first : elements) { 
    Attribute newAttribute = first.getAttribute(); 

    for (final Element second : elements) { 
     if (!first.equals(second)) { 
      newAttribute = newAttribute.add(computeChange(first, second)); 
     } 
    } 
    final Element newElement = new Element(first.getEntry(), newAttribute, first.getValue()); 
    updated.add(newElement); 
} 

Poi, ho provato molte variazioni di espressioni lambda, il più semplice dei quali è:

elements.parallelStream() 
     .map(first -> new Element(first.getEntry(), first.getAttribute().add(
     computeChange(first, second)), first 
     .getValue())).collect(Collectors.toList())); 

Ovviamente, questo è sbagliato in quanto non v'è alcuna riferimento al secondo disponibile per me e nessuna condizione/filtro per il secondo non uguale al primo.

Come ridurre questo ciclo annidato con condizionale restituendo una raccolta a un'espressione lambda?

Qualsiasi aiuto qui è molto apprezzato.

+3

Questo è difficile perché il vostro 'newAttribute = newAttribute.add (...)' aggiornamenti non sono parallelizzabile. Ciò sarebbe più semplice se fosse possibile aggregare tutti i risultati di 'computeChange' e quindi creare un' Attributo' (o 'Element') da quell'aggregato. –

+0

Vorrei lasciarlo così com'è. –

+0

Cosa restituisce 'computeChange'? Un 'elemento',' attributo' o un numero? –

risposta

3

Prova:

elements.stream() 
    .map(first -> { 
     Attribute newAttribute = elements.stream().filter(second -> !first.equals(second)) 
       .map(second -> computeChange(first, second)) 
       .reduce(first.getAttribute(), (a, b) -> a.add(b)) 
       return new Element(first.getEntry(), newAttribute, first.getValue()); 
      }).collect(Collectors.toList())); 
+4

Non penso che questo '.foreach (newAttribute :: add);' funzionerà, dato che 'add' sembra creare un nuovo attributo. Forse 'ridurre' funzionerà, però. –

+0

@tobias_k il foreach segnala l'errore: Il metodo foreach (Attribute :: add) non è definito per il tipo Stream . L'utilizzo di reduce elimina l'errore. – Todd

+0

pgerstoft, @tobias_k Ho avuto bisogno di cambiare l'argomento di foreach/reduce per essere Attributo: aggiungi altrimenti ho ricevuto l'errore "Il tipo Attributo non definisce add (Attributo, Attributo) che è applicabile qui". Tuttavia, non sto superando i test unitari, quindi non penso che l'aggiornamento/aggiunta ripetuta funzioni correttamente. Continuerò a stuzzicarlo, ma se hai qualche suggerimento, mi piacerebbe ascoltarli. – Todd