Reputation: 1693
I know how to sort by an attribute from this question where the top answer suggests doing:
someList.sort(key=lambda x: x.someAttr, reverse=True)
and I have seen suggestions for sorting a sublist which suggest to do something like:
someList[i:j] = sorted(somelist[i:j])
but how can I sort a sublist by an attribute? I tried:
someList[i:j].sort(key=lambda x: x.someAttr, reverse=True)
but this did not work. Any suggestions?
Upvotes: 0
Views: 255
Reputation: 22953
The reason your last method didn't work is because you're trying to sort the sublist in-place. When you do:
L[1:-1].sort(...)
You're basically creating a copy of the sublist L[1:-1]
. But because you sorted the copy in place, no reference was ever made to copy, and the new sorted list was lost and later garbage collected.
Instead, you need to reassign the new sorted value of the sublist, to the old sublist. eg:
>>> 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]
Here's an example pertaining more to your specific case:
>>> 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)]
Upvotes: 2
Reputation: 402423
You're on the right track. You can sort a sublist with sorted()
and assign it to the same splice. Here's an example:
>>> 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)]
This has sorted the middle two elements. For your use case, don't forget the reverse=True
keyword argument in the call.
On a related note, someList[i:j].sort(key=lambda x: x.someAttr, reverse=True)
doesn't work as you expected. Well, it does sort a sublist, however, when you splice the original list, you end up creating an anonymous copy and sorting that in-place, and then losing that sorted copy (it is not assigned to anything, it is garbage collected). The original list is not affected.
Upvotes: 4