2010-03-01 3 views
8

appare quanto segue il mio codice Python 2.6:Ugly combinazione di generatore di espressione per ciclo

for src, dst in ([s,d] for s in universe for d in universe if s != d): 

Posso fare molto meglio? Ciò che in particolare non mi piace è che in effetti sto specificando la stessa coppia due volte, una volta per il ciclo for e ancora per l'espressione del generatore. Non sono sicuro se preferirei:

for src, dst in itertools.product(universe, universe): 
    if src != dst: 

C'è un modo per esprimere questo ciclo in modo conciso?

universe sembra essere una lista, se fa alcuna differenza. L'ordine di iterazione non ha importanza.

+0

Che tipo di routine richiede/consente un prodotto incrociato come questo? –

+0

Penso che il tuo codice sia bello, il primo esempio è più chiaro da capire rispetto all'altro. – dalloliogm

+0

@Ignacio: Sto costruendo un grafico a 2 vie i cui nodi sono gli elementi di 'universe', e che sarà elaborato da qualche altro software altrove che si aspetta un insieme di spigoli. Ho il codice per calcolare l'esistenza e il peso di ogni spigolo: se ti aiuta puoi supporre che questa sia una funzione 'make_edge (src, dst)', che restituisce una descrizione. Le soluzioni che usano 'map' o altre funzioni correlate per chiamare' make_edge' sono plausibili, e forse la cosa giusta da fare, ma trasformare il corpo del ciclo for in una funzione non è meno una ripetizione di quello che ho già, quindi non lo fa risolvere quel problema AFAIK. –

risposta

5

Si potrebbe utilizzare semplice annidati per-loop:

for src in universe: 
    for dst in universe: 
     if src == dst: 
     continue 
     ... 

direi che questo è il più facile da leggere la sintassi in questo caso.

+0

Potresti avere ragione. Lo odio quando il codice puramente imperativo è il più semplice ;-) –

+0

Accettando questa risposta, che ho letto come "no, non puoi fare * molto * meglio" ... –

1

itertools.product possibile portare una "ripetizione" argomento parola chiave se si vuole avere la stessa sequenza più di un parametro:

itertools.product(universe, repeat=2) 

si tratta di una questione di opinione sul fatto che questo è più leggibile.

è possibile sostituire il codice originale con:

for (src, dest) in filter(lambda (a,b): a!=b, itertools.product(universe, repeat=2)): 
    ... 
+0

Bello. Non sapevo che potessi farlo. –

+0

Come stai usando un 'filter' con un' lambda', non costa molto di più da fare 'for (src, dest) in ((a, b) per a, b in itertools.product (universe, repeat = 2) if a! = b): '. ** NOTA: ** Che fa lo stesso. Sì. Il mio punto è lasciare che OP decida qual è il più leggibile. – JeromeJ

3

Suggerisco mantenere del tutto funzionale o interamente con comprensioni. Ecco un'implementazione completamente funzionale.

import itertools 
import operator 

def inner_product(iterable): 
    "the product of an iterable with itself" 
    return itertools.product(iterable, repeat=2) 

def same(pair): 
    "does this pair contain two of the same thing?" 
    return operator.is_(*pair) 

universe = 'abcd' 

pairs = inner_product(universe) 
unique_pairs = itertools.ifilterfalse(same, pairs) 
for pair in unique_pairs: 
    print pair 

""" 
('a', 'b') 
('a', 'c') 
('a', 'd') 
('b', 'a') 
('b', 'c') 
('b', 'd') 
('c', 'a') 
('c', 'b') 
('c', 'd') 
('d', 'a') 
('d', 'b') 
('d', 'c') 
""" 
+0

Mi piace in linea di principio. In pratica, il codice potrebbe essere mantenuto da persone che non conoscono/a malapena Python, quindi non penso di osare effettivamente usarlo questa volta. –