2014-06-25 17 views
19

Durante la programmazione in Python, ora evito map, lambda e filter utilizzando le list comprehensions perché è più facile da leggere e più veloce nell'esecuzione. Ma è possibile sostituire anche lo reduce?python: può essere tradotto in una lista comprensibile come map, lambda e filter?

E.g. un oggetto ha un operatore union() che funziona su un altro oggetto, a1.union(a2) e fornisce un terzo oggetto dello stesso tipo.

Ho un elenco di oggetti:

L = [a1, a2, a3, ...] 

Come avere l'unione() di tutti questi oggetti con list comprehension, l'equivalente di:

result = reduce(lambda a, b :a.union(b), L[1:], L[0]) 
+1

In alcuni casi: n. Ma dipende Si prega di fornire una query specifica che avete in mente – sshashank124

+1

@ sshashank124 - qualche esempio? – mhawke

+0

Le unioni di set sono un cattivo esempio, perché puoi semplicemente fare 'result = set(). Union (* L)', che ha il vantaggio di funzionare anche se L è una lista vuota. Ad ogni modo, 'lambda a, b: a.union (b)' può essere scritto in modo più conciso come 'set.union', poiché in python' obj.method (args) 'è lo stesso di' cls.method (obj , args) ' – Eric

risposta

3

Non proprio. La comprensione delle liste è più simile a map e probabilmente a filter.

3

Poiché una comprensione di lista genera in modo definitivo un altro elenco, non è possibile utilizzarlo per generare un singolo valore. Non sono per. (Beh ... c'è uno this nasty trick che usa un dettaglio di implementazione trapelato nelle vecchie versioni di Python che può farlo. Non sto nemmeno andando a copiare il codice di esempio qui. Non fare questo.)

Se si Sei preoccupato per gli aspetti stilistici di reduce() e il suo tipo, non essere. Dai un nome alle tue riduzioni e starai bene. Così, mentre:

all_union = reduce(lambda a, b: a.union(b), L[1:], L[0]) 

non è grande, in questo modo:

def full_union(input): 
    """ Compute the union of a list of sets """ 

    return reduce(lambda a, b: a.union(b), input[1:], input[0]) 

result = full_union(L) 

è abbastanza chiaro.

Se siete preoccupati per velocità, Scopri i toolz e cytoolz pacchetti, che sono rispettivamente 'veloce' e 'follemente veloce,'. Su dataset di grandi dimensioni, spesso consentono di evitare l'elaborazione dei dati più di una volta o di caricare l'intero set in memoria in una sola volta, in contrasto con le list comprehensions.

+0

Per rendere leggibile l'espressione 'reduce()', rendere il primo argomento non un lambda. Ad esempio: 'riduci (set.union, )' A volte questo richiederà di definire (e quindi nominare) l'operatore da qualche parte al di fuori della chiamata a 'reduce'. – Jordan

16

Non è un segreto che ridurre è not among the favored functions dei Pythonistas.

Genericamente, reduce è un left fold on a list

E 'concettualmente facile scrivere una piega in Python che si piega a sinistra oa destra su un iterabile:

def fold(func, iterable, initial=None, reverse=False): 
    x=initial 
    if reverse: 
     iterable=reversed(iterable) 
    for e in iterable: 
     x=func(x,e) if x is not None else e 
    return x 

Senza qualche trucco atroce, questo non può essere replicata in una comprensione perché non c'è funzione di tipo accumulatore in una comprensione.

Basta usare ridurre - o scrivere quello che ha più senso per voi.

1

Un uso comune di riduzione consiste nell'appiattire un elenco di elenchi. Puoi invece usare una comprensione di lista.

L = [[1, 2, 3], [2, 3, 4], [3, 4, 5]] 

con ridurre

from functools import reduce # python 3 
flattened = reduce(lambda x, y: x + y, L) 

print(flattened) 

[1, 2, 3, 2, 3, 4, 3, 4, 5] 

con la lista d'

flattened = [item for sublist in L for item in sublist] 

print(flattened) 

[1, 2, 3, 2, 3, 4, 3, 4, 5] 

Se il problema può essere risolto agendo sulla lista appiattita, questo è un sostituto efficace. Contrastare queste one-liner per l'esempio dato:

all_union = reduce(lambda a, b: set(a).union(set(b)), L) 

{1, 2, 3, 4, 5} 

all_union = set([item for sublist in L for item in sublist]) 

{1, 2, 3, 4, 5} 
+0

Usa 'sum (L, [])'. Detto questo, la comprensione somma/lista crea un elenco "a lunghezza intera", dove 'riduci (operator.or_, map (set, L), set())' non lo farebbe. –