2013-12-11 5 views
5

Caveat: questa è una domanda verso l'alto per il codice-golf, quindi so quello che sto chiedendo è cattiva pratica nella produzioneAlterare un elenco utilizzando accoda nel corso di una lista di comprensione

sto cercando di alterare un array durante la comprensione di una lista, ma per qualche motivo è sospeso e non so perché o come risolverlo.

Ho a che fare con un elenco di elenchi di profondità indeterminata e ho bisogno di condensarli in un elenco semplice - for those curious its this question. Ma a questo punto, diciamo solo che ho bisogno di un elenco semplice di tutti gli elementi nell'elenco e 0 se è un elenco.

Il metodo normale è quello di scorrere la lista e se un elenco aggiungerlo alla fine, in questo modo:

for o in x: 
if type(o)==type([]):x+=o 
else:i+=o 
print i 

Sto cercando di accorciare questa lista di comprensione utilizzando, in questo modo.

print sum([ 
[o,x.append(o) or 0][type(o)==type([])] 
for o in x 
])) 

Ora, so List.append restituisce None, in modo da assicurare che ho un valore numerico, la valutazione pigra dice che posso fare x.append(o) or 0, e dal momento che None è "falsy" sarà evaulate la seconda parte e il valore è 0.

Ma non è così. Se inserisco x.append() nella comprensione della lista oltre x, non si rompe o non si restituisce un errore, o restituisce un errore di iterazione, semplicemente si blocca. Perché il blocco append durante la comprensione dell'elenco, ma il ciclo for sopra funziona correttamente?

edit: Per mantenere questa domanda l'eliminazione, io non sono alla ricerca di suggerimenti golf (sono molto educativo però), che era alla ricerca di una risposta sul motivo per cui il codice non funzionava come ho l'avevo scritto

+0

Off-topic per questa domanda, ma per il problema originale: non sarebbe più semplice appiattire l'iteratore nidificato in un iteratore (che è possibile eseguire in una funzione a 2 righe in 3.3+, una funzione a 3 righe senza, se non è possibile utilizzare moduli di terze parti come 'more-itertools'), quindi basta scrivere il codice triviale su quell'iteratore? – abarnert

+0

@abarnert 'from itertools import *' è lungo 22 caratteri, quindi è necessario chiamare il metodo effettivo. Il che è un bel prezzo da pagare solo per una biblioteca. –

+0

'sum (map (lambda x: x% 2-.5, flatten (a)))' ha solo 37 caratteri. 22 + 1 + 37 = 60, che certamente batte il 73 che c'è adesso. – abarnert

risposta

8

or può essere pigro, ma le definizioni di lista non lo sono. Per ogni o in x, quando il [o,x.append(o) or 0][type(o)==type([])] mostruosità viene valutata, Python deve valutare [o,x.append(o) or 0], che significa valutare x.append(o) or 0, il che significa che o verrà aggiunto alla x indipendentemente dal fatto che una lista. Così, si finisce con ogni elemento di x allegata alla x, e poi ottenere di nuovo aggiunto e ancora e ancora e OutOfMemoryError

+0

Non ho dovuto aspettare abbastanza a lungo per vedere l'errore. tavolo da disegno suppongo :( –

+1

@LegoStormtroopr: Se sei su 6 Python a 4 bit, su una piattaforma che espande lo swap in base alle esigenze (come per default OS X e Windows), l'errore potrebbe non colpire fino a dopo ore di swap thrashing ... – abarnert

3

Che dire:

y = [element for element in x if type(element) != list or x.extend(element)] 

(si noti che extend si appiattisce, mentre append sarà aggiungi solo la lista annidata alla fine, non appiattita).

+2

Perché non fare semplicemente 'type (element)! = List '? 'list' * è * il tipo di' [] '. – mgilson

+0

Ahem, giusto! Stavo alterando il codice di @ Lego e sono stato portato con il vento :) Grazie! Corretto! – Roberto

+0

Golf brillante, ma in realtà non risponde alla domanda. Tuttavia, non potrei in buona coscienza presentare questa come la mia soluzione alla sfida e suggerire invece di farlo. –

Problemi correlati