2013-04-30 17 views
5

Ho bisogno di costruire un generatore e stavo cercando un modo per accorciare questo per loop in una sola riga. Ho provato a elencare ma non ha funzionato.C'è un modo per abbreviare questa espressione del generatore Python?

counter=0 
for element in string: 
    if function(element): 
     counter+=1 
     yield counter 
    else: 
     yield counter 
+1

Ti manca un 'counter = 0', o si suppone che sia una chiusura attorno a qualsiasi cosa 'counter' è nel codice esterno? – abarnert

+0

Quale versione di Python? – Blender

+0

No, l'ho escluso inizialmente, ma l'ho appena incluso. – garlfd

risposta

6
counter=0 
for element in string: 
    counter+=bool(function(element)) 
    yield counter 

(Sì, aggiungendo booleani per interi funziona esattamente come se fosse True1 e False era 0).

Il bool() chiamata è richiesta solamente se function() possono avere valori di ritorno diversi True, False, 1 e 0.

4

Se si sta utilizzando Python 3, si può fare:

from itertools import accumulate 

yield from accumulate(1 if function(x) else 0 for x in string) 

Anche se io userei Simeon Visser's answer. Mentre questo può essere breve, non è immediatamente chiaro cosa fa il codice.

+0

@jamylak: non ti rimane una variabile 'counter' alla fine. – Blender

+0

Questo non funzionerà a meno che 'function' restituisca esplicitamente 0 e 1. Se restituisce, ad esempio,' None' o una stringa, otterrai dappertutto 'TypeError'. Anche se restituisce 'True' e' False', il primo valore sarà 'False' invece di' 0'. – abarnert

+0

Non sono sicuro di cosa significhi "sto assumendo' accumula' restituisce un valore booleano ". Restituisce un iteratore. Ed è un iteratore su qualunque tipo di addable tu gli dai (o, piuttosto, sul risultato dell'aggiunta di qualunque tipo tu gli dai, non proprio la stessa cosa, perché, ad esempio, 'False + True == 1', o, in precedenza Python, '(1 << 31) + (1 << 31) = (1L << 32)'). – abarnert

3

Si potrebbe accorciare a:

counter=0 
for element in string: 
    if function(element): 
     counter+=1 
    yield counter 
+0

Ho bisogno di tenere un conto corrente, quindi ho bisogno di cedere anche con la dichiarazione else. – garlfd

+2

@garlfd: ​​questo produce ancora con ogni elemento della stringa, lo aggiorna solo per alcuni elementi. –

4

In primo luogo, è possibile trasformare la stringa in un iteratore sui valori function di ritorno:

truths = (function(x) for x in string) 

Quindi è possibile mappare quelli di 0 e 1:

onesandzeroes = (1 if function(x) else 0 for x in string) 

E poi li accumulate:

running = itertools.accumulate(1 if function(x) else 0 for x in string) 

Come da nota della nota, accumulate è stato aggiunto in Python 3.2. Se si utilizza 2.x, è possibile copiare e incollare la ricetta "Equivalente a" dai documenti. (Se stai usando 3.0-3.1, puoi fare lo stesso, ma in questo caso, basta aggiornare.)

Problemi correlati