2010-03-01 10 views
8

siguiente aparece en mi Python 2.6 código:combinación feo de expresión generador con bucle para

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

¿Puedo hacer mucho mejor? Lo que particularmente no me gusta es que estoy especificando el mismo par dos veces, una para el ciclo for y otra para la expresión del generador. No estoy seguro de si preferiría:

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

¿Hay alguna manera de expresar este ciclo concisamente?

universe es una lista, si hace alguna diferencia. El orden de iteración no importa.

+0

¿Qué tipo de rutina requiere/permite un producto cruzado como este? –

+0

Creo que su código es bueno, el primer ejemplo es más claro de entender que el otro. – dalloliogm

+0

@Ignacio: Estoy construyendo un gráfico bidireccional cuyos nodos son los elementos del 'universo', y que será procesado por algún otro software en otro lugar que espera un conjunto de bordes. Tengo un código para calcular la existencia y el peso de cada borde: si te ayuda, puedes asumir que se trata de una función 'make_edge (src, dst)', que devuelve una descripción. Las soluciones que usan 'map' u otras funciones relacionadas para llamar' make_edge' son plausibles, y quizás lo correcto, pero convertir el cuerpo del bucle for en una función no es menos repetitivo de lo que ya lo hice, por lo que no arreglar ese problema AFAIK. –

Respuesta

5

Usted podría utilizar sencilla anidada para-bucles:

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

yo diría que este es el más fácil de leer sintaxis en este caso.

+0

Es posible que tenga razón. Odio cuando el código puramente imperativo es el más simple ;-) –

+0

Al aceptar esta respuesta, que leo como "no, no se puede hacer * mucho * mejor" ... –

1

itertools.product puede tomar una "repetición" argumento de palabra clave si se quiere tener la misma secuencia que más de un parámetro:

itertools.product(universe, repeat=2) 

que es una cuestión de opinión en cuanto a si esto es más fácil de leer.

podría reemplazar el código original con:

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

Agradable. No sabía que pudieras hacer eso. –

+0

Como está utilizando un 'filtro' con un' lambda', no cuesta mucho más hacer 'for (src, dest) en ((a, b) para a, b en itertools.product (universe, repeat = 2) si a! = b): '. ** NOTA: ** Lo cual hace lo mismo. Sí. Mi punto es dejar que OP decida cuál es el más legible. – JeromeJ

3

Sugiero manteniéndola totalmente funcional o en su totalidad con comprensiones. Aquí hay una implementación que es completamente funcional.

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

Me gusta esto en principio. En la práctica, el código puede ser mantenido por personas que no conocen apenas Python, así que no creo que me atreva a usarlo esta vez. –

Cuestiones relacionadas