如何根据对象的属性对对象列表进行排序?
我有一个 Python 对象列表,我想按每个对象的特定属性进行排序:
[Tag(name="toe", count=10), Tag(name="leg", count=2), ...]
How do I sort the list by .count
inscending order?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
对列表进行就地排序:
要返回新列表,请使用
sorted
:说明:
key=lambda x: x.count
按计数排序。reverse=True
按降序排序。有关按键排序的更多信息。
To sort the list in place:
To return a new list, use
sorted
:Explanation:
key=lambda x: x.count
sorts by count.reverse=True
sorts in descending order.More on sorting by keys.
最快的方法是使用
operator.attrgetter("count")
,特别是当您的列表有很多记录时。 但是,这可能会在 Python 的预运算符版本上运行,因此最好有一个后备机制。 那么您可能想要执行以下操作:A way that can be fastest, especially if your list has a lot of records, is to use
operator.attrgetter("count")
. However, this might run on an pre-operator version of Python, so it would be nice to have a fallback mechanism. You might want to do the following, then:读者应该注意到 key= 方法:
比向对象添加丰富的比较运算符快很多倍。 我很惊讶地读到了这篇文章(《Python in a Nutshell》第 485 页)。 您可以通过在这个小程序上运行测试来确认这一点:
我的,非常小的测试显示第一个排序慢了 10 倍以上,但书上说它通常只慢了 5 倍左右。 他们这么说的原因是由于Python中使用的高度优化的排序算法(timsort)。
不过,很奇怪的是 .sort(lambda) 比普通的旧 .sort() 更快。 我希望他们能解决这个问题。
Readers should notice that the key= method:
is many times faster than adding rich comparison operators to the objects. I was surprised to read this (page 485 of "Python in a Nutshell"). You can confirm this by running tests on this little program:
My, very minimal, tests show the first sort is more than 10 times slower, but the book says it is only about 5 times slower in general. The reason they say is due to the highly optimizes sort algorithm used in python (timsort).
Still, its very odd that .sort(lambda) is faster than plain old .sort(). I hope they fix that.
面向对象的方法
最好将对象排序逻辑(如果适用)作为类的属性,而不是将其合并到需要排序的每个实例中。
这确保了一致性并消除了对样板代码的需要。
您至少应该指定
__eq__
和__lt__
操作才能使其正常工作。 然后只需使用sorted(list_of_objects)
。Object-oriented approach
It's good practice to make object sorting logic, if applicable, a property of the class rather than incorporated in each instance the ordering is required.
This ensures consistency and removes the need for boilerplate code.
At a minimum, you should specify
__eq__
and__lt__
operations for this to work. Then just usesorted(list_of_objects)
.它看起来很像 Django ORM 模型实例的列表。
为什么不在查询中对它们进行排序,如下所示:
It looks much like a list of Django ORM model instances.
Why not sort them on query like this:
如果您要排序的属性是属性,那么您可以避免导入operator.attrgetter并使用属性的
fget
方法代替。例如,对于具有属性
radius
的类Circle
,我们可以按半径对circle
列表进行排序,如下所示:这不是最好的- 已知的功能,但通常可以节省我的导入时间。
If the attribute you want to sort by is a property, then you can avoid importing
operator.attrgetter
and use the property'sfget
method instead.For example, for a class
Circle
with a propertyradius
we could sort a list ofcircles
by radii as follows:This is not the most well-known feature but often saves me a line with the import.
向对象类添加丰富的比较运算符,然后使用列表的 sort() 方法。
请参阅Python 中的丰富比较。
更新:虽然这种方法可行,但我认为 Triptych 的解决方案更适合您的情况,因为方法更简单。
Add rich comparison operators to the object class, then use sort() method of the list.
See rich comparison in python.
Update: Although this method would work, I think solution from Triptych is better suited to your case because way simpler.
另外,如果有人想要对包含字符串和数字的列表进行排序,例如,
那么这里是代码:
Also if someone wants to sort list that contains strings and numbers for e.g.
Then here is the code for that:
@Jose M Vidal 的答案提到了一些重要的事情:使用丰富的比较(
__lt__
、__eq__
等,如 @jpp 的答案)使得排序比传递关键函数慢得多(如已接受的答案)。 然而,他们最终展示了一个使用 Python 3 中不存在的 __cmp__ 方法的测试(tbf 确实比 Python 2 中传递密钥慢得多)。我想指出的是,即使在 Python 3.12.0 中,使用 @jpp 的答案中的丰富比较也会使排序比传递关键函数慢得多。
下面显示了一些 timeit 测试的结果,其中比较了使用丰富比较进行排序与 lambda 键函数与
operator.attrgetter
作为键的排序。 对于包含 10k 项的列表,使用丰富比较时大约花费 18.8 毫秒,而使用 lambda 键函数时花费 2.93 毫秒,使用operator.attrgetter
时花费 2.47 毫秒。因此,正如 @tzot 提到的,operator.attrgetter 比 lambda 更快; 然而,首先使用关键函数而不是丰富的比较可以使排序速度提高 5 倍以上。
@Jose M Vidal's answer mentions something important: using rich comparisons (
__lt__
,__eq__
etc. as in @jpp's answer) makes sorting much slower than passing a key function (as in the accepted answer). However, they end up showing a test using__cmp__
method which doesn't exist in Python 3 (which tbf was indeed so much slower than passing key in Python 2).I want to point out that even in Python 3.12.0, using rich comparisons as in @jpp's answer makes sorting much slower than passing a key function.
The results of a little timeit test is shown below where sorting using rich comparisons vs a lambda key function vs
operator.attrgetter
as key are compared. For a list with 10k items, it took about 18.8 ms when rich comparisons were used whereas it took 2.93 ms when a lambda key function was used and 2.47 ms whenoperator.attrgetter
was used.So, as @tzot mentioned,
operator.attrgetter
is faster than a lambda; however, using a key function in the first place instead of rich comparisons makes sorting over 5 times faster.