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

2024-11-28 08:37:00
admin
原创
12
摘要:问题描述:我有一个 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
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   649  
  如何借鉴华为IPD体系优化企业研发?在当今竞争激烈的市场环境中,企业要想保持技术领先和产品竞争力,必须拥有一套高效且严谨的研发管理体系。华为作为全球领先的ICT解决方案提供商,其集成产品开发(IPD, Integrated Product Development)体系与质量管理体系(如ISO 9000系列)的融合实践,...
IPD项目管理   0  
  IPD流程图的7种经典绘制方法详解在产品开发领域,集成产品开发(Integrated Product Development,简称IPD)流程被广泛应用,以提高产品开发的效率和质量。IPD流程图作为这一流程的可视化工具,其绘制方法至关重要。本文将详细介绍七种经典的IPD流程图绘制方法,帮助项目管理人员和团队更好地理解和...
IPD研发管理体系   0  
  IPD流程:企业创新管理的核心引擎在当今快速变化的市场环境中,企业要想持续保持竞争力,就必须不断进行创新。而IPD(Integrated Product Development,集成产品开发)流程作为一种先进的产品开发管理模式,正逐渐成为众多企业提升创新能力、加速产品上市速度、降低开发成本的重要选择。本文将深入探讨IP...
IPD管理   0  
  IPD流程与传统产品开发流程的概述在产品开发领域,企业不断寻求高效、系统的管理方法以确保产品能够顺利从概念转化为市场成功的产品。集成产品开发(Integrated Product Development,简称IPD)流程与传统产品开发流程是两种截然不同的管理理念和方法。传统产品开发流程往往以职能部门为核心,各部门按顺序...
IPD流程中PDCP是什么意思   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用