2015-07-05 10 views
7

Perché lo lazy è utilizzato qui?Pigrizia in Swift

extension SequenceType { 
    func mapSome<U>(transform: Generator.Element -> U?) -> [U] { 
     var result: [U] = [] 
     for case let x? in lazy(self).map(transform) { 
      result.append(x) 
     } 
     return result 
    } 
} 

questa estensione prende una funzione di trasformazione che restituisce un optional, e restituisce un array di solo quei valori che non sono stati trasformati in nil

Perché non usare self.map(transform)? la pigrizia è necessaria qui?

+0

A proposito, 'flatMap (trasformazione: Generator.Element -> U?) -> [U] 'è ora disponibile nella libreria standard Swift 2 :) – jtbandes

risposta

11

Evita la creazione di un array intermedio.

self.map(transform) 

restituisce un matrice contenente i risultati della trasformazione di tutti elementi di sequenza, che sarebbe poi traslato per costruire il risultante matrice con gli elementi non nulli.

lazy(self).map(transform) 

è una sequenza degli elementi trasformati, che è poi iterata per ottenere gli elementi non nulli. Gli elementi trasformati vengono calcolati durante l'enumerazione. (Ogni chiamata a next() sulla sequenza artificiale produce un elemento trasformando il successivo elemento della sequenza originale.)

Entrambi i metodi funzionano. Il metodo lazy potrebbe probabilmente migliorare per sequenze di grandi dimensioni, ma ciò può dipendere da molti fattori (la dimensione della matrice, indipendentemente dal fatto che gli elementi siano tipi di valore o di riferimento, quanto costosa sia la copia degli elementi dell'array ecc.). Per i piccoli array il metodo lazy potrebbe essere più lento a causa del sovraccarico aggiuntivo . In un'applicazione concreta, la creazione di profili con gli strumenti sarebbe per decidere quale metodo utilizzare.

+1

I miei test di prestazione (dichiaratamente informali) suggeriscono che i pigri e quelli non pigri si comportano in modo identico per piccoli array, ma che i pigri danno un vantaggio modesto a quelli più grandi quelli, quindi vale la pena includere (specialmente in una funzione di libreria come questa). È interessante notare che 'flatMap', che a partire da 2.0 ora ha questa stessa logica, si comporta peggio di entrambi. –

+0

@AirspeedVelocity: È interessante, grazie per il feedback. –

+0

È interessante notare che ho ottenuto il risultato opposto !? Vedi la mia risposta qui sotto. – Qbyte

5

Come ha detto Martin R lazy(), si evita la creazione di un array intermedio. Tuttavia, se si confronta il tempo di esecuzione della funzione su array di dimensioni diverse, si scopre che lazy() è "solo" il 10% più veloce.

È interessante notare che lo lazy() è per gli array con meno di 200 elementi fino a 2 volte più veloci e ottiene con più elementi quasi la stessa velocità della funzione senza la conversione (10% più veloce).

(Testato con Xcode 6.4 e Xcode 7 con funzioni globali e protocollo di estensione in un parco giochi come (compilato) file sorgente)

Così lazy() preferirebbe essere utilizzati per Sequences in cui non si sa se è finita . Poi, per i cicli sono probabilmente utilizzato con break o return:

for element in lazy(sequence).map{ ... } { 
    if element == 1000 { 
     break 
    } 
    // use element 
} 

Se si chiama mappa su una infinita Sequence (come 1,2,3 ...) l'esecuzione sarebbe anche infinita. Con lazy() la trasformazione e l'esecuzione vengono "ritardate" in modo da poter gestire sequenze "grandi" e infinite in modo più efficiente se si esce dal ciclo prima dell'ultimo elemento.