2009-10-10 26 views
5

Tengo algunos objetos personalizados y diccionarios que quiero ordenar. Quiero ordenar tanto los objetos de los diccionarios juntos. Quiero ordenar los objetos por un atributo y los diccionarios por una clave.Ordenar una lista heterogénea de objetos en Python

object.name = 'Jack' 
d = {'name':'Jill'} 

sort_me =[object, d] 

¿Cómo puedo ordenar esta lista usando el atributo del nombre del objeto y la tecla 'nombre' del diccionario?

Respuesta

8

Lo que seguramente está buscando es utilizar la opción key = para sorted(), que proporciona una función que devuelve una clave de clasificación arbitraria para cada elemento. Esta función puede verificar el tipo de su argumento y tomar varias acciones. Por ejemplo:

import types 

class obj(object): 
    def __init__(self, arg): 
     self.name = arg 

def extract_name(obj): 
    if type(obj) is types.DictType: 
     return obj['name'] 
    else: 
     return obj.__dict__['name'] 

d = { 'name': 'Jill'}  
print sorted([obj('Jack'), d], key=extract_name) 

Más información se puede encontrar en la sugerencia de utilizar la isinstance Python wiki

de RichieHindle es una buena. Y mientras yo estaba en que pensé que sería bueno para apoyar a los nombres de elementos arbitrarios en lugar de codificar 'nombre':

def extract_elem_v2(elem_name): 
    def key_extractor(obj): 
     dct = obj if isinstance(obj, dict) else obj.__dict__ 
     return dct[elem_name] 
    return key_extractor 

que se puede utilizar de esta manera:

print sorted(list_of_stuff, key=extract_elem_v2('name')) 
+3

+1. Sugerencia menor: 'isinstance (obj, dict)' sería más nítido, y permitiría las clases derivadas de 'dict'. – RichieHindle

+0

Tienes razón, la instancia es una mejor opción allí, no estoy seguro de por qué no pensé en eso. Versión actualizada adjunta a la respuesta. ¡Gracias! –

+0

¡Muchas gracias, Jack! Esta respuesta es hermosa. – hekevintran

2
sort_me.sort(key=attr_or_itemgetter('name')) 

Dónde attr_or_itemgetter() :

class attr_or_itemgetter(object): 
    def __init__(self, name): 
     self.name = name 
    def __call__(self, obj): 
     try: return getattr(obj, name) 
     except AttributeError: 
      return obj[name] 

NOTA: Se intencionadamente no comprueba el tipo de diccionario, por lo tanto, attr_or_itemgetter('items') aplicado a un diccionario devolverá el método dict.items.

+1

Encuentro esta respuesta más pitonica que la basada en la verificación de tipo (puede ser un poco más lenta si hay muchos dicts en la secuencia que se está ordenando, pero solo se necesita optimizarla para ese uso es voltear lo que es el cuerpo de prueba y qué es el cuerpo excepto, y atrapar diferentes excepciones; -0). –

1

Esto funcionó para mí. Tenga en cuenta que sort() no devuelve la lista ordenada, pero sorted() sí, por lo que si desea pasar esto a una plantilla, debe usar sorted en los parámetros, o sort antes de pasar la lista como parámetro.

itemized_action_list = list(chain(detection_point.insertbodyaction_set.all(), 
            detection_point.insertheaderaction_set.all(), 
            detection_point.modifybodyaction_set.all(), 
            detection_point.modifyheaderaction_set.all(), 
            detection_point.removebodyaction_set.all(), 
            detection_point.removeheaderaction_set.all(), 
            detection_point.redirectaction_set.all())) 

sorted(itemized_action_list, key=attrgetter('priority')) 
+0

Bienvenido a SO. Intenta ser claro y preciso en tus ejemplos. Sin información adicional, no es posible decir qué contiene tu lista. – joaquin