2009-10-10 6 views
5

J'ai quelques objets et dictionnaires personnalisés que je veux trier. Je veux trier les deux objets les dictionnaires ensemble. Je veux trier les objets par un attribut et les dictionnaires par une clé. Comment trier cette liste en utilisant l'attribut name de l'objet et la clé 'name' du dictionnaire?Tri d'une liste hétérogène d'objets en Python

Répondre

8

Ce que vous cherchez presque certainement, c'est d'utiliser l'option key = pour tried(), qui fournit une fonction qui renvoie une clé de tri arbitraire pour chaque élément. Cette fonction peut vérifier le type de son argument et effectuer diverses actions. Par exemple:

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) 

Plus d'informations sont disponibles sur la suggestion du Python wiki

RichieHindle d'utiliser isinstance est un bon. Et pendant que j'y étais, je pensais que ce serait bien de soutenir les noms d'éléments arbitraires au lieu de coder en dur « nom »:

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 vous pouvez utiliser comme ceci:

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

+1. Suggestion mineure: 'isinstance (obj, dict)' serait plus net et autoriserait les classes dérivées de 'dict'. – RichieHindle

+0

Vous avez raison, isinstance est un meilleur choix là-bas, je ne sais pas pourquoi je n'ai pas pensé à ça. Version mise à jour ajoutée à la réponse. Merci! –

+0

Merci beaucoup Jack! Cette réponse est belle. – hekevintran

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

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] 

REMARQUE: Il ne vérifie pas intentionnellement pour le type dictionnaire, donc attr_or_itemgetter('items') appliqué à un dictionnaire renverra la méthode dict.items.

+1

Je trouve cette réponse plus Pythonic que celle basée sur la vérification de type (peut être un peu plus lent s'il y a beaucoup de dicts dans la séquence à trier, mais tout ce qu'il faut pour l'optimiser cette utilisation est renversant quel est le corps d'essai et quel est le corps excepté, et attraper différentes exceptions; -0). –

1

Cela a fonctionné pour moi. Notez que sort() ne renvoie pas la liste triée, mais sorted() fait, donc si vous voulez passer à un modèle, vous devez utiliser sorted dans les paramètres, ou sort avant de passer la liste en tant que paramètre.

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

Bienvenue sur SO. Essayez d'être clair et précis dans vos exemples. Sans informations supplémentaires, il n'est pas possible de dire ce que contient votre liste. – joaquin