2012-06-01 12 views
18

le permite asumir el siguiente objeto simple:objeto por su miembro dentro de una lista en Python

class Mock: 
    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

entonces tengo una lista con algunos objetos como este:

myList = [Mock("Dan", 34), Mock("Jack", 30), Mock("Oli", 23)...] 

¿Hay alguna incorporado en la característica donde puedo obtener todos los simulacros con una edad de, por ejemplo, 30? Por supuesto que se pueden repetir a mí mismo por encima de ellos y comparar sus edades, sino algo así como

find(myList, age=30) 

estaría bien. ¿Hay algo como eso?

Respuesta

32

Es posible que desee comprobar la validez de indexarlos -

from collections import defaultdict 

class Mock(object): 
    age_index = defaultdict(list) 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 
     Mock.age_index[age].append(self) 

    @classmethod 
    def find_by_age(cls, age): 
     return Mock.age_index[age] 

Editar: una imagen vale más que mil palabras:

enter image description here

X axis es el número de Mocks en myList, el eje Y es el tiempo de ejecución en segundos.

  • puntos rojos son @ filtro de dcrooney método()
  • puntos azules son @ lista por comprensión de marshall.ward
  • puntos verdes se esconden detrás del eje X son mi índice ;-)
+0

Muchas gracias por esta respuesta. Estaba a punto de volver a implementar algo similar de forma manual. – xlash

+2

Gracias.Y buen diagrama. Pero sería útil discutir las diferentes compensaciones, p. tiempo extra de inicio para construir el índice y el espacio requerido para ello. – nealmcb

34

Usted podría intentar un filter():

filter(lambda x: x.age == 30, myList) 

Esto sería devolver una lista con sólo los objetos que satisface la expresión lambda.

+3

Y si usted planea en hacer una búsqueda por esta propiedad, a menudo, es posible que desee mantener un 'dict' basado en el atributo. –

+1

Al menos para Python 3.5, necesita 'list (filter (lambda x: x.age == 30, myList))' para obtener una lista. – CGFoX

+1

El uso de 'filter()' es la antigua respuesta clásica, pero las listas de comprensión son más rápidas y más portátiles en todas las versiones de Python, como se explica en otras respuestas. – nealmcb

19

listas por comprensión pueden recoger estos:

new_list = [x for x in myList if x.age == 30] 
+0

buena solución, también, pero la respuesta @dcrooney se ajusta más a la función. ¿Alguien comparó cuál es más rápido? –

+1

'timeit' da aproximadamente 0.30 usec para la comprensión de la lista y 0.58 para el filtro lambda en mi máquina. Pero son esencialmente equivalentes aquí, por lo que debe usar el que prefiera. –

+2

Algunas buenas discusiones sobre el problema aquí también: http://stackoverflow.com/a/1247490/317172 –

5

Lista las comprensiones son casi siempre la manera más rápida de hacer estas cosas (2 veces más rápido aquí), aunque como se mencionó anteriormente, la indexación es aún más rápida si le preocupa la velocidad.

~$ python -mtimeit -s"from mock import myList" "filter(lambda x: x.age==21, myList)" 
1000000 loops, best of 3: 1.34 usec per loop 
~$ python -mtimeit -s"from mock import myList" "[x for x in myList if x.age==21]" 
1000000 loops, best of 3: 0.63 usec per loop 

Para archivo mock.py en el directorio actual:

class Mock: 
    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

myList = [Mock('Tom', 20), Mock('Dick', 21), Mock('Harry', 21), Mock('John', 22)] 
Cuestiones relacionadas