2009-10-10 20 views
5

Ho alcuni oggetti personalizzati e dizionari che voglio ordinare. Voglio ordinare entrambi gli oggetti insieme ai dizionari. Voglio ordinare gli oggetti con un attributo e i dizionari con una chiave.Ordinamento di un elenco di oggetti eterogeneo in Python

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

sort_me =[object, d] 

Come si ordina questo elenco utilizzando l'attributo nome dell'oggetto e il tasto "nome" del dizionario?

risposta

8

Quello che quasi sicuramente stai cercando è utilizzare l'opzione key = per sorted(), che fornisce una funzione che restituisce una chiave di ordinamento arbitraria per ogni elemento. Questa funzione può controllare il tipo di argomento e intraprendere varie azioni. Per esempio:

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) 

Maggiori informazioni possono essere trovate sul suggerimento Python wiki

di RichieHindle di utilizzare isinstance è un buon compromesso. E mentre ero a che ho pensato che potrebbe essere bello per sostenere i nomi degli elementi arbitrari anziché hardcoding 'name':

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 

che è possibile utilizzare in questo modo:

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

+1. Suggerimento minore: 'isinstance (obj, dict)' sarebbe più ordinato e consentirebbe alle classi derivate da 'dict'. – RichieHindle

+0

Hai ragione, isinstance è una scelta migliore lì, non sono sicuro del perché non ci ho pensato. Versione aggiornata aggiunta alla risposta. Grazie! –

+0

Grazie mille Jack! Questa risposta è bella. – hekevintran

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

Dove 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: volutamente non controlla per il tipo di dizionario, quindi attr_or_itemgetter('items') applicato a un dizionario restituirà il metodo dict.items.

+1

Trovo questa risposta più Pythonic di quella basata sul controllo dei tipi (potrebbe essere un po 'più lento se ci sono molti dts nella sequenza che viene ordinata, ma tutto ciò che serve per ottimizzarlo per quell'uso sta capovolgendo qual è il corpo di prova e qual è il corpo eccetto, e prendendo differenti eccezioni; -0). –

1

Questo ha funzionato per me. Notare che sort() non restituisce l'elenco ordinato, ma lo fa sorted(), quindi se si desidera passare a un modello, è necessario utilizzare sorted nei parametri o sort prima di passare l'elenco come parametro.

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

Benvenuti in SO. Cerca di essere chiaro e preciso nei tuoi esempi. Senza nessuna informazione aggiuntiva non è possibile dire cosa contiene la tua lista. – joaquin

Problemi correlati