Python按对象属性对子列表进行排序

时间:2017-07-03 19:57:35

标签: python sorting

我知道如何根据this问题中的一个属性进行排序,其中最佳答案建议:

someList.sort(key=lambda x: x.someAttr, reverse=True)

我已经看到了对子列表进行排序的建议,该子列表建议执行以下操作:

someList[i:j] = sorted(somelist[i:j])

但是如何按属性对子列表进行排序?我试过了:

someList[i:j].sort(key=lambda x: x.someAttr, reverse=True)

但这不起作用。有什么建议吗?

2 个答案:

答案 0 :(得分:4)

你走在正确的轨道上。您可以使用sorted()对子列表进行排序,并将其分配给同一个拼接。这是一个例子:

>>> class Foo:
...    def __init__(self, val):
...        self.val = val
...    def __repr__(self): 
...        return 'Foo(%d)' %self.val
...
>>>
>>> x = [Foo(5), Foo(3), Foo(2), Foo(7)]
>>> x
[Foo(5), Foo(3), Foo(2), Foo(7)]
>>> x[1:3] = sorted(x[1:3], key=lambda x: x.val)
>>> x
[Foo(5), Foo(2), Foo(3), Foo(7)]

这已经对中间两个元素进行了排序。对于您的用例,请不要忘记调用中的reverse=True关键字参数。

在相关说明中,someList[i:j].sort(key=lambda x: x.someAttr, reverse=True)无法按预期工作。好吧,它会对子列表进行排序,但是,当您拼接原始列表时,最终会创建一个匿名副本并就地排序,然后丢失该排序副本(它没有分配给任何东西,它是垃圾收集的) 。原始列表不受影响。

答案 1 :(得分:2)

您的上一个方法无效的原因是您尝试将子列表就地排序。当你这样做时:

L[1:-1].sort(...)

您基本上是在创建子列表L[1:-1] 副本 。但是因为你对副本进行了排序,所以没有引用复制,新的排序列表丢失了,后来又被垃圾收集了。

相反,您需要将子列表的新排序值重新分配给旧子列表。例如:

>>> l = [1, 3, 2, 4, 5]
>>> l[1:-1].sort() # Reference to sorted sublist is never saved
>>> l # List unchanged
[1, 3, 2, 4, 5]
>>> l[1:-1] = sorted(l[1:-1]) # Reassign the sorted sublist to the old one
>>> l # List is modfied
[1, 2, 3, 4, 5]

以下是一个与您的具体情况有关的示例:

>>> class UserId:
...     def __init__(self, id_number):
...         self.id_number = id_number
...     def __repr__(self):
...         return 'UserId(id_number={})'.format(self.id_number)
... 
>>> user_ids = [UserId(1), UserId(3), UserId(4), UserId(2), UserId(5)]
>>> user_ids[1:-1] = sorted(user_ids[1:-1], key=lambda u: u.id_number, reverse=True)
>>> user_ids
[UserId(id_number=1), UserId(id_number=4), UserId(id_number=3), UserId(id_number=2), UserId(id_number=5)]