Usando le funzioni di ordine superiore per applicare m out di M filtro e quindi trasformare i dati di dimensione n?

1

Numero totale: di filtri possibili è M. L'utente può selezionare m filtri dove m < = M. Un tipico esempio sono i file di una cartella, si potrebbe dire modificati tra così e così la data, iniziare con così e così e così via.

meets = []
for each in something:
    if user_filter1:
       if user_filter1_condition_met:
          meets.append(True)
    #hardcode all other filters here
    if all(meets):
          do_something(each)

    else:
       meets = True
       for each in something:
           do_something(each)

Qui ripeto di nuovo l'intero codice, che è contro i principi di DRY.

for each in something:
    if user_filter:
       if not filter_condition_met:
          continue
    do_something(each)

Qui sto facendo il controllo del filtro per tutti gli elementi del ciclo, mentre essenzialmente deve essere fatto una sola volta.

Posso utilizzare le funzioni di ordine superiore per controllare una volta le condizioni del filtro e generare un codice che fa il lavoro? Sembra un filtro e quindi trasforma l'operazione. Qualcuno può dare qualche idea?

Un addendum alla domanda con un'essenza simile:

def function(inner,outer):
      for each in outer:
           for each in inner:
                 print "Something"

#Border condition inner doesn't exist I need a code object that goes like this:

def function(inner,outer):
      for each in outer:
           print "Something"

#Inner doesn't exist , so I want to to not go a for each in inner operation i. 
#I mean it won't change the complexity of the problem at hand
#But suppose there are billions elements , I save billion for each in [].
    
posta Nishant 30.12.2014 - 22:10
fonte

3 risposte

1

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!")
    
risposta data 31.12.2014 - 11:03
fonte
1

Here I am doing the filter check for all items in the loop, while essentially it needs to be done just once.

Perché è un problema?

Scrivi il codice nel modo più pulito possibile. Se ha senso strutturare il codice con il test booleano eseguito più volte, quindi scrivilo in questo modo.

Evita ottimizzazioni non necessarie, per citare Knuth, "l'ottimizzazione prematura è la radice di tutti i mali" .

    
risposta data 30.12.2014 - 23:12
fonte
0

Qualcosa di simile è ciò che volevo: (Applicando un caso d'uso di esempio che potrei inventare)

predicates = []

if filenamme:
   predicates.append(lambda x,filename: x.name == filename)
if from_dt and to_dt:
   predicates.append(lambda x, from_dt, to_date: from_dt <= x.mod_dt <= to_dt)

for file in files:
    if all(predicate(file) for each in predicates):
       do_something(file)

Volevo generare i miei predicati all'esterno.

    
risposta data 30.12.2014 - 23:29
fonte

Leggi altre domande sui tag