如何根据对象的属性对对象列表进行排序?

2024-11-28 08:37:00
admin
原创
157
摘要:问题描述:我有一个 Python 对象列表,我想按每个对象的特定属性进行排序:[Tag(name="toe", count=10), Tag(name="leg", count=2), ...] .count如何按降序对列表进行排序?解决方案 1:对列表进行排序:ori...

问题描述:

我有一个 Python 对象列表,我想按每个对象的特定属性进行排序:

[Tag(name="toe", count=10), Tag(name="leg", count=2), ...]

.count如何按降序对列表进行排序?


解决方案 1:

对列表进行排序:

orig_list.sort(key=lambda x: x.count, reverse=True)

要返回新列表,请使用sorted

new_list = sorted(orig_list, key=lambda x: x.count, reverse=True)

解释:

  • key=lambda x: x.count按计数排序。

  • reverse=True按降序排序。

有关按键排序的更多信息。

解决方案 2:

一种最快的方法是使用,特别是当你的列表有很多记录时operator.attrgetter("count")。但是,这可能在 Python 的预操作版本上运行,因此最好有一个回退机制。然后,你可能想要执行以下操作:

try: import operator
except ImportError: keyfun= lambda x: x.count # use a lambda if no operator module
else: keyfun= operator.attrgetter("count") # use operator since it's faster than lambda

ut.sort(key=keyfun, reverse=True) # sort in-place

解决方案 3:

读者应该注意到key=方法:

ut.sort(key=lambda x: x.count, reverse=True)

比向对象添加丰富的比较运算符要快很多倍。我很惊讶地读到这个(《Python 简明教程》第 485 页)。您可以通过对这个小程序运行测试来确认这一点:

#!/usr/bin/env python
import random

class C:
    def __init__(self,count):
        self.count = count

    def __cmp__(self,other):
        return cmp(self.count,other.count)

longList = [C(random.random()) for i in xrange(1000000)] #about 6.1 secs
longList2 = longList[:]

longList.sort() #about 52 - 6.1 = 46 secs
longList2.sort(key = lambda c: c.count) #about 9 - 6.1 = 3 secs

我的测试结果显示,第一次排序的速度慢了 10 倍以上,但书中说,一般来说,它只慢了 5 倍左右。他们说的原因是 Python 中使用的排序算法高度优化 ( timsort )。

不过,.sort(lambda) 比普通的 .sort() 更快,这很奇怪。我希望他们能解决这个问题。

解决方案 4:

面向对象方法

如果适用的话,最好将对象排序逻辑作为类的属性,而不是将其纳入每个需要排序的实例中。

这确保了一致性并且消除了对样板代码的需要。

至少,您应该指定__eq____lt__操作以使它工作。然后只需使用sorted(list_of_objects)

class Card(object):

    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __eq__(self, other):
        return self.rank == other.rank and self.suit == other.suit

    def __lt__(self, other):
        return self.rank < other.rank

hand = [Card(10, 'H'), Card(2, 'h'), Card(12, 'h'), Card(13, 'h'), Card(14, 'h')]
hand_order = [c.rank for c in hand]  # [10, 2, 12, 13, 14]

hand_sorted = sorted(hand)
hand_sorted_order = [c.rank for c in hand_sorted]  # [2, 10, 12, 13, 14]

解决方案 5:

from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)

解决方案 6:

它看起来很像 Django ORM 模型实例的列表。

为什么不像这样对查询进行排序:

ut = Tag.objects.order_by('-count')

解决方案 7:

如果您想要排序的属性是属性那么您可以避免导入operator.attrgetter,而使用属性的fget方法。

例如,对于Circle具有属性的类,radius我们可以按半径对列表进行排序,circles如下所示:

result = sorted(circles, key=Circle.radius.fget)

这不是最著名的功能,但经常可以帮助我节省导入的行数。

解决方案 8:

向对象类添加丰富的比较运算符,然后使用列表的 sort() 方法。

请参阅python 中的丰富比较。


更新:虽然这种方法可行,但我认为 Triptych 的解决方案更适合您的情况,因为它更简单。

解决方案 9:

另外如果有人想对包含字符串和数字的列表进行排序,例如

 eglist=[
     "some0thing3",
     "some0thing2",
     "some1thing2",
     "some1thing0",
     "some3thing10",
     "some3thing2",
     "some1thing1",
     "some0thing1"]

下面是该代码:

import re

def atoi(text):
    return int(text) if text.isdigit() else text

def natural_keys(text):
    return [ atoi(c) for c in re.split(r'(d+)', text) ]

eglist=[
         "some0thing3",
         "some0thing2",
         "some1thing2",
         "some1thing0",
         "some3thing10",
         "some3thing2",
         "some1thing1",
         "some0thing1"
]

eglist.sort(key=natural_keys)
print(eglist)

解决方案 10:

@Jose M Vidal 的回答提到了一些重要的事情:使用丰富的比较(__lt____eq__@jpp 的回答中的 等)会使排序比传递 key 函数(如接受的答案)慢得多。但是,他们最终展示了一个使用__cmp__Python 3 中不存在的方法的测试(坦白说,这确实比在 Python 2 中传递 key 慢得多)。

我想指出的是,即使在 Python 3.12.0 中,使用@jpp 的答案中的丰富比较也会使排序比传递关键函数慢得多。

下面显示了一个小型 timeit 测试的结果,其中比较了使用丰富比较、lambda 键函数和作为键的排序。对于包含 10k 个项目的列表,使用丰富比较时大约需要 18.8 毫秒,而使用 lambda 键函数时需要 2.93 毫秒,使用operator.attrgetter时需要 2.47 毫秒。operator.attrgetter

因此,正如 @tzot 提到的,operator.attrgetter它比 lambda 更快;但是,首先使用键函数而不是丰富的比较可以使排序速度提高 5 倍以上。

import timeit
import random
from operator import attrgetter

class Card(object):

    def __init__(self, rank):
        self.rank = rank

    def __eq__(self, other):
        return self.rank == other.rank

    def __lt__(self, other):
        return self.rank < other.rank

n = 100
random.seed(0)
lst = [Card(random.randrange(10000)) for _ in range(10000)]


min(timeit.repeat(lambda: sorted(lst), number=n))/n
# 0.018813106999732553

min(timeit.repeat(lambda: sorted(lst, key=lambda card: card.rank), number=n))/n
# 0.0029304770001908763

min(timeit.repeat(lambda: sorted(lst, key=attrgetter('rank')), number=n))/n
# 0.00247172600007616
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用