Concettualmente, ogni filtro è un predicato - una funzione che fornisce un input, restituisce true o false. La funzione python filter(function, iterable)
accetta un predicato e un iterabile e restituisce solo gli elementi che il predicato è vero per Quindi quello che vuoi è un modo per combinare tutti i filtri che un utente seleziona nel filtro uno , che corrisponde solo se tutti corrispondono. La funzione all
può essere utilizzata qui, all(iterable)
restituisce true solo se ogni elemento di iterable
è vero. Usando questo, possiamo combinare predicati:
def andPredicate(predicates):
def pred(v):
return all((p(v) for p in predicates))
return pred
La funzione andPredicates
accetta un elenco di predicati e ne fornisce uno nuovo che restituisce solo true per un elemento se tutti i predicati restituiscono true per quell'elemento. Ad esempio, se hai predicati isNumber
e isLessThanZero
, puoi definire isNegativeNumber
come segue:
isNegativeNumber = andPredicate([isNumber, isLessThanZero])
print(isNegativeNumber("foo")) # False
print(isNegativeNumber(8)) # False
print(isNegativeNumber(-5)) # True
Quindi questo ti consente di combinare i filtri. Se hai un elenco di filtri, in cui ogni filtro è un predicato, puoi fare questo:
filteredItems = filter(andPredicate(userFilters), items)
Fatto e fatto. L'iterabile viene ripetuto una volta sola e i filtri vengono controllati uno alla volta su un oggetto finché non si verifica un errore. Se uno fallisce, il resto dei filtri viene saltato e viene preso l'elemento successivo, se tutti riescono, quindi l'elemento è incluso nell'ultimo iterabile. Nota che filter
produce una lista in Python 2.xe un iteratore in Python 3.x.
Inoltre, la definizione di andPredicates
può essere ulteriormente abbreviata con una funzione anonima, ma potrebbe non essere chiara ai lettori del tuo codice se non hanno familiarità con i modelli di programmazione funzionale:
def andPredicate(predicates):
return lambda v: all((p(v) for p in predicates))
Per completezza, ecco le definizioni dei predetti isNumber
e isLessThanZero
:
from numbers import Number
def isNumber(v):
return isinstance(v, Number)
def isLessThanZero(x):
return x < 0
Nella seconda parte della tua domanda, vuoi fare qualcosa una volta per ogni elemento nel prodotto incrociato di due elenchi, o vuoi fare qualcosa una volta per ogni elemento nel secondo elenco del primo elenco è vuoto. Il modulo itertools
contiene una funzione product
che fondamentalmente fa la stessa cosa di nested for loops. Ad esempio invece di questo:
for a in as:
for b in bs:
print("Something!")
Puoi scrivere questo:
from itertools import product
for a, b in product(as, bs):
print("Something!")
Entrambi i pezzi di codice sono equivalenti. Tuttavia, quando uno dei file iterabili è vuoto, l'intero prodotto è vuoto, proprio come nei loop annidati. Possiamo scrivere la nostra versione di product
che invece di essere vuota quando uno dei iterabili è vuoto, è vuota solo quando entrambi sono vuoti e se uno è vuoto , quindi restituisce semplicemente i valori nell'altro iterabile e utilizza None
come valori per il primo iterabile. Questo può essere definito in questo modo:
from itertools import product
def productWithNones(as, bs):
if as and bs:
return product(as, bs)
if as:
return product(as, [None])
if bs:
return product([None], bs)
return []
Ora questo:
for a, b in productWithNones([1, 2, 3], []):
print((a, b))
Stampa questo:
(1, None)
(2, None)
(3, None)
Invece di essere semplicemente vuoti. Quindi il tuo ciclo originale può essere scritto come:
for eachOuter, eachInner in productWithNones(outer, inner):
print("Something!")