2009-02-28 8 views
50

Supongamos que estoy creando una clase simple para que funcione de forma similar a una estructura de estilo C, solo para contener elementos de datos. Estoy intentando descubrir cómo buscar una lista de objetos para objetos con un atributo que iguale un cierto valor. A continuación se muestra un ejemplo trivial para ilustrar lo que estoy tratando de hacer.Búsqueda de una lista de objetos en Python

Por ejemplo:

class Data: 
    pass 

myList = [] 

for i in range(20): 
    data = Data() 
    data.n = i 
    data.n_squared = i * i 
    myList.append(data) 

¿Cómo hago para buscar en la lista myList para determinar si contiene un elemento con n == 5?

He estado buscando en Google y buscando en los documentos de Python, y creo que podría hacer esto con una lista de comprensión, pero no estoy seguro. Debo añadir que, por cierto, tengo que usar Python 2.4.3, por lo que no tengo a mi disposición ninguna característica nueva de gee-whiz 2.6 o 3.x.

+0

Tal vez un capricho involuntario de su ejemplo: myList = [Datos() n == 0, Datos() n = 1.. , ...] donde data.n sería asignado por range() y data.n sería el índice en myList. Por lo tanto, le permite extraer cualquier instancia de Data() simplemente haciendo referencia a myList por un valor de índice. Por supuesto, puede modificar posteriormente myList [0] .n = 5.2 o algo así. Y el ejemplo quizás fue demasiado simplificado. – DevPlayer

Respuesta

66

, usted puede obtener una lista de todos elementos que coinciden con una lista por comprensión:

[x for x in myList if x.n == 30] # list of all elements with .n==30 

Si simplemente quiere determinar si la lista contiene cualquier elemento que coincida y lo haga (relativamente) eficientemente, puede hacer

def contains(list, filter): 
    for x in list: 
     if filter(x): 
      return True 
    return False 

if contains(myList, lambda x: x.n == 3) # True if any element has .n==3 
    # do stuff 
+19

o, cualquiera (filtro_personalizado (x) para x en myList si x.n == 30) que es solo su función "contiene" como una función integrada. – nosklo

+0

Error de sintaxis en nosklo: necesita un conjunto adicional de() alrededor del generador. – gahooa

+0

No es así. Pruébalo y mira. –

1

se debe añadir un método y una __eq____hash__ a su clase Data, se podría comprobar si los atributos son iguales (__dict__ mismas propiedades) y luego, si sus valores son iguales, también.

Si hiciera eso, puede utilizar

test = Data() 
test.n = 5 

found = test in myList 

Los in cheques de palabras clave si es test en myList.

Si sólo desea aa n propiedad en Data puede usar:

class Data(object): 
    __slots__ = ['n'] 
    def __init__(self, n): 
     self.n = n 
    def __eq__(self, other): 
     if not isinstance(other, Data): 
      return False 
     if self.n != other.n: 
      return False 
     return True 
    def __hash__(self): 
     return self.n 

    myList = [ Data(1), Data(2), Data(3) ] 
    Data(2) in myList #==> True 
    Data(5) in myList #==> False 
25
[x for x in myList if x.n == 30]    # list of all matches 
any(x.n == 30 for x in myList)     # if there is any matches 
[i for i,x in enumerate(myList) if x.n == 30] # indices of all matches 

def first(iterable, default=None): 
    for item in iterable: 
    return item 
    return default 

first(x for x in myList if x.n == 30)   # the first match, if any 
+0

Esta es una buena respuesta debido al "primer" método, que es probablemente el caso de uso más común. – galarant

36

simplemente para la corrección, no olvidemos la más simple cosa que podría trabajar posiblemente:

for i in list: 
    if i.n == 5: 
    # do something with it 
    print "YAY! Found one!" 
24
filter(lambda x: x.n == 5, myList) 
+23

para alguien que quiere aprender Python, entender que lambda es básico. – vartec

+1

Bueno, sí y no - con la lista de comprensiones y clasificación de las funciones clave de los fabricantes como operator.attrgetter, casi nunca uso 'lambda's. –

7

Puede utilizar in para buscar un elemento en una colección, y una liste la comprensión para extraer el campo que le interesa. Esto (funciona para listas, conjuntos, tuplas y cualquier cosa que defina __contains__ o __getitem__).

if 5 in [data.n for data in myList]: 
    print "Found it" 

Consulte también:

46

simple, elegante y de gran alcance:

Una expresión generadora en conjunción con una orden interna ... (pyt hon 2.5+)

any(x for x in mylist if x.n == 10) 

Utiliza la orden interna de Python any(), que se define de la siguiente manera:

cualquier (iterable)-> Retorno True si cualquier elemento del iterable es cierto. Equivalente a:

def any(iterable): 
    for element in iterable: 
     if element: 
      return True 
    return False 
+0

Agradable. FYI usted puede hacer cualquier (x para x en mylist si x.n == 10) para guardar algunos parens (también == not =). –

3

considerar el uso de un diccionario:

myDict = {} 

for i in range(20): 
    myDict[i] = i * i 

print(5 in myDict) 
+0

O: d = dict ((i, i * i) para i en el rango (20)) – hughdbrown

+0

Resuelve el problema trivial que solía ilustrar mi pregunta, pero realmente no resolvió mi pregunta de raíz. La respuesta que estaba buscando (hace más de 5 años) era la comprensión de la lista. :) – m0j0

Cuestiones relacionadas