2010-11-20 13 views
15

Esiste un Python idiomatico e/o elegante per zippare e applicare un elenco di funzioni su un elenco di valori?Zip e applicare un elenco di funzioni su un elenco di valori in Python

Ad esempio, si supponga di avere una lista di funzioni:

functions = [int, unicode, float, lambda x: '~' + x + '~'] 

e un elenco di valori:

values = ['33', '\xc3\xa4', '3.14', 'flange'] 

C'è un modo per applicare la funzione i-esimo al valore-esima e ritorno una lista della stessa lunghezza dei valori trasformati, evitando questa brutta lista di comprensione?

[functions[i](values[i]) for i in range(len(functions))] # <- ugly 

Quello che voglio è qualcosa di simile zip() + map() (zipmap()!) L'elenco delle funzioni con l'elenco dei valori e hanno le funzioni di essere applicati ai loro valori associati. Ho pensato che itertools potrebbe offrire qualcosa di rilevante, ma funzioni come imap e starmap sono per mappare una singola funzione su un iterabile, non un iterable di funzioni su un altro iterabile.

+0

Sono propenso a dire che il compito che si sta desiderando è una specie di brutto in sé, quindi ci si dovrebbe aspettare l'attuazione di essere - come tu lo giudichi - anche brutto. – msw

+2

@msw Penso che il compito sia piuttosto comune - pensa di trasformare i grezzi bytestrings in oggetti Python da un file CSV o simili, quindi l'elenco di funzioni potrebbe provenire da una colonna che contiene altri metadati come i dati della colonna, ecc. –

+1

@msw: Metti la testa dentro un database medio e vedi quanto può essere brutto un database quando nessuno si preoccupa di scrivere un brutto codice per convalidarlo. –

risposta

16

Queste soluzioni sembrano eccessivamente complicato: map cerniere già i suoi argomenti:

map(lambda x,y:x(y), functions, values) 

O, se si preferisce la versione iteratore:

from itertools import imap 
imap(lambda x,y:x(y), functions, values) 
20
[x(y) for x, y in zip(functions, values)] 
+0

Per essere onesti, speravo in una soluzione non basata sulla comprensione dell'elenco, non importa quanto elegante, e certamente il tuo è - stavo cercando una soluzione applicativa funzionale, preferibilmente dalla libreria standard. Ma il tuo è pratico, conciso e non brutto :) –

+0

Giusto - immagino intendevo, una pura funzione di applicazione in contrapposizione alla sintassi. Ma il punto è stato preso :) –

+2

@Paul Smith, uno dei motivi per cui questo tipo di cose non ha bisogno di essere coperto dalla libreria standard è che Python ha delle liste di comprensione. Sono parte integrante della lingua e dovrebbero essere usati dove appropriato. Sono appropriati qui. – aaronasterling

4

Una delle più belle caratteristiche dell'incapsulazione funzionale è che possono nascondere la bruttezza.

Se avete bisogno di zipmap, definirlo:

def zipmap(values, functions): 
    return [functions[i](values[i]) for i in range(
     len(functions))] 
1

Codice che è pensato per funzionare in modo robusto w ould fare questo in un ciclo for in modo da poter fornire significativa segnalazione degli errori:

for i in xrange(num_columns): 
    try: 
     outrow.append(functions[i](input_values[i]) 
    except (ValueError, EtcetcError) as e: 
     self.do_error_reporting(row_number, i, input_value[i], e) 
     outrow.append(None) 
Problemi correlati