在Python中对一个异构对象列表进行排序

5

我有一些自定义对象和字典需要排序。我希望同时对对象和字典进行排序。我想通过属性对对象进行排序,通过键对字典进行排序。

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

sort_me =[object, d]

我该如何使用对象的名称属性和字典的“name”键来对此列表进行排序?
4个回答

8
你可能正在寻找的是使用sorted()中的key=选项,它提供了一个函数,为每个元素返回一个任意的排序键。该函数可以检查其参数的类型并执行各种操作。例如:
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)

更多信息可以在Python维基上找到。
RichieHindle建议使用isinstance是一个好主意。而且当我在做这件事情的时候,我认为支持任意元素名称可能会更好,而不是硬编码“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

您可以这样使用:

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

3
小建议:isinstance(obj, dict) 更加简洁,也允许从 dict 派生的类。 - RichieHindle
你说得对,isinstance 在那里是更好的选择,不确定为什么我没有想到。更新版本已添加到答案中。谢谢! - Jack Lloyd
非常感谢你,杰克!这个答案很棒。 - hekevintran
1
并非所有对象都可用__dict__属性。 - jfs
A) 在行内进行更正,这是人们阅读的方式。type(..) is 这个东西没有任何保留的价值。 B) vars(obj) 是否比 obj.__dict__ 更受欢迎?(vars 是一个不太知名的内置函数。) - u0b34a0f6ae

3
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]

注意:该函数故意不检查字典类型,因此将 attr_or_itemgetter('items') 应用于字典将返回 dict.items 方法。


2
我认为这个答案比基于类型检查的答案更符合Pythonic风格(如果要排序的序列中有大量字典,则可能会慢一些,但只需翻转try体和except体中的内容,并捕获不同的异常即可针对该用途进行优化;-0)。 - Alex Martelli

1
这对我有用。请注意,sort()不会返回排序后的列表,但是sorted()会返回,因此如果您想将其传递给模板,则应在参数中使用sorted,或者在将列表作为参数传递之前使用sort
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'))

欢迎来到 SO。在您的示例中尽量清晰和精确。如果没有其他信息,就不可能说出您的列表包含什么。 - joaquin

1

新列表 = [10,"m",20,30,"a","r",70,"d"]

def 函数名(x):

if type(x) == str:

    return ord(x)+100

return x

new_list.sort(key=func)

打印(new_list)

[10, 20, 30, 70, 'a', 'd', 'm', 'r']


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接