2009-09-28 12 views
5

Howdy, codeboys y codegirls!Evaluando en dos o más listas

Me he encontrado con un problema simple con la solución aparentemente fácil. Pero al ser un neófito de Python siento que hay un mejor enfoque en alguna parte.

Supongamos que tiene una lista de cadenas mixtas. Hay dos tipos básicos de cadenas en el saco: las que tienen "=" en ellas (a = potato) y las que no tienen (Lady Jane). Lo que necesita es clasificarlos en dos listas.

El enfoque obvia es:

for arg in arguments: 
    if '=' in arg: 
     equal.append(arg) 
    else: 
     plain.append(arg) 

¿Hay alguna otra manera, más elegante en ella? Algo como:

equal = [arg for arg in arguments if '=' in arg] 

pero para ordenar en listas múltiples?

¿Y si tiene más de un tipo de datos?

+3

Creo que su enfoque obvio es perfectamente bueno y mucho más legible que muchas de las respuestas sugerido hasta ahora! –

+0

De hecho, creo que la lista de comprensiones es una de las características más elegantes de Python que anhelo constantemente mientras escribo C++. 2 de ellos son mucho más agradables que cualquiera de las respuestas – Steg

Respuesta

4

Trate

for arg in arguments: 
    lst = equal if '=' in arg else plain 
    lst.append(arg) 

o (santa fea)

for arg in arguments: 
    (equal if '=' in arg else plain).append(arg) 

Una tercera opción: Crear una clase que ofrece append() y que clasifica en varias listas.

+0

Encuentro más legible la forma 'list = ('=' en arg) e igual o simple'. – giorgian

+0

está sombreando el built-in – SilentGhost

+0

Creo que "a if cond else b" es un inglés muy legible; Simplemente no me gusta poner demasiado en una sola línea. –

4

Se puede utilizar para este itertools.groupby():

import itertools 
f = lambda x: '=' in x 
groups = itertools.groupby(sorted(data, key=f), key=f) 
for k, g in groups: 
    print k, list(g) 
+3

Pensé que pedía elegante – Steg

+0

La clasificación hace nlog (n) mientras existe una solución O (n) más simple. –

1

Otro enfoque es utilizar la función filter, aunque no es la solución más eficiente.
Ejemplo:

>>> l = ['a=s','aa','bb','=', 'a+b'] 
>>> l2 = filter(lambda s: '=' in s, l) 
>>> l3 = filter(lambda s: '+' in s, l) 
>>> l2 
['a=s', '='] 
>>> l3 
['a+b'] 
2
def which_list(s): 
    if "=" in s: 
     return 1 
    return 0 

lists = [[], []] 

for arg in arguments: 
    lists[which_list(arg)].append(arg) 

plain, equal = lists 

Si usted tiene más tipos de datos, añadir una cláusula if a which_list, e inicializar lists a listas más vacías.

+0

which_list puede ser mucho más simple - ver mi respuesta. De lo contrario, nuestras respuestas son bastante cercanas. – PaulMcG

+0

De hecho, puede ser, pero el OP preguntó sobre el caso de más de dos posibilidades, que quería tratar en el diseño inicial. –

+0

En ese caso, creo que un diccionario de listas sería más claro. Los índices de lista no tienen sentido. –

3

Me gustaría obtener dos listas de comprensión. Si bien eso implica cierta sobrecarga (dos bucles en la lista), es más pitónico usar una lista de comprensión que usar un for. También es (en mi opinión) mucho más legible que usar todo tipo de trucos realmente geniales, pero que menos gente conoce.

1

Puse todo esto en orden, y luego veo que Ned Batchelder ya estaba en este mismo rumbo. Sin embargo, elegí empaquetar el método de división en lugar del selector de listas, y simplemente usar los valores 0/1 implícitos para Falso y Verdadero.

def split_on_condition(source, condition): 
    ret = [],[] 
    for s in source: 
     ret[condition(s)].append(s) 
    return ret 

src = "z=1;q=2;lady jane;y=a;lucy in the sky".split(';') 

plain,equal = split_on_condition(src, lambda s:'=' in s) 
1

Su enfoque es el mejor. Para clasificar solo en dos listas, no puede ser más claro que eso. Si usted quiere que sea una sola línea, encapsular en una función:

def classify(arguments): 
    equal, plain = [], [] 
    for arg in arguments: 
     if '=' in arg: 
      equal.append(arg) 
     else: 
      plain.append(arg) 
    return equal, plain 


equal, plain = classify(lst) 
2

me gustaría ir para el enfoque de Edan, por ejemplo,

equal = [arg for arg in arguments if '=' in arg] 
plain = [arg for arg in arguments if '=' not in arg] 
2

leí en alguna parte aquí que usted puede estar interesado en una solución que va a trabajar para más de dos identificadores (signo igual y el espacio).

la siguiente solución sólo requiere actualizar el uniques conjunto con cualquier cosa que quisiera hacer juego, los resultados se colocan en un diccionario de listas con el identificador como la clave.

uniques = set('= ') 
matches = dict((key, []) for key in uniques) 

for arg in args: 
    key = set(arg) & uniques 
    try: 
     matches[key.pop()].append(arg) 
    except KeyError: 
     # code to handle where arg does not contain = or ' '. 

Ahora el código anterior asume que sólo tendrá un solo partido para su identificador en su arg. Es decir, que no tiene un arg que se parece a este 'John= equalspace'. También tendrá que pensar en cómo le gustaría tratar los casos que no coinciden con nada en el conjunto (KeyError se produce)