根据多个属性对列表进行排序?

2024-11-29 08:42:00
admin
原创
136
摘要:问题描述:我有一个清单:[[12, 'tall', 'blue', 1], [2, 'short', 'red', 9], [4, 'tall', 'blue', 13]] 如果我想按一个元素排序,比如说高/矮元素,我可以通过 来实现s = sorted(s, key = itemgetter(1))。如果我...

问题描述:

我有一个清单:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]

如果我想按一个元素排序,比如说高/矮元素,我可以通过 来实现s = sorted(s, key = itemgetter(1))

如果我想按高/矮和颜色排序我可以进行两次排序,每个元素一次,但有没有更快的方法?


解决方案 1:

键可以是返回元组的函数:

s = sorted(s, key = lambda x: (x[1], x[2]))

或者您可以使用以下方法实现相同的目的itemgetter(这更快并且避免了 Python 函数调用):

import operator
s = sorted(s, key = operator.itemgetter(1, 2))

请注意,这里您可以使用sort而不是使用sorted然后重新分配:

s.sort(key = operator.itemgetter(1, 2))

解决方案 2:

我不确定这是否是最符合 Python 风格的方法...我有一个元组列表,需要先按降序整数值排序,再按字母顺序排序。这需要反转整数排序,但不需要反转字母排序。这是我的解决方案:(顺便说一句,在考试中,我甚至不知道你可以“嵌套”排序函数)

a = [('Al', 2),('Bill', 1),('Carol', 2), ('Abel', 3), ('Zeke', 2), ('Chris', 1)]  
b = sorted(sorted(a, key = lambda x : x[0]), key = lambda x : x[1], reverse = True)  
print(b)  
[('Abel', 3), ('Al', 2), ('Carol', 2), ('Zeke', 2), ('Bill', 1), ('Chris', 1)]

解决方案 3:

虽然迟到了几年,但我想同时根据 2 个标准进行排序使用reverse=True。如果其他人想知道怎么做,您可以将标准(函数)括在括号中:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)

解决方案 4:

看来您可以使用 alist代替 a tuple。我认为,当您抓取属性而不是列表/元组的“魔法索引”时,这一点变得更加重要。

在我的例子中,我想按类的多个属性进行排序,其中传入的键是字符串。我需要在不同的地方进行不同的排序,并且我希望客户端与之交互的父类有一个通用的默认排序;只有当我真的“需要”时才需要覆盖“排序键”,而且我还可以将它们存储为类可以共享的列表

所以我首先定义了一个辅助方法

def attr_sort(self, attrs=['someAttributeString']:
  '''helper to sort by the attributes named by strings of attrs in order'''
  return lambda k: [ getattr(k, attr) for attr in attrs ]

然后使用它

# would defined elsewhere but showing here for consiseness
self.SortListA = ['attrA', 'attrB']
self.SortListB = ['attrC', 'attrA']
records = .... #list of my objects to sort
records.sort(key=self.attr_sort(attrs=self.SortListA))
# perhaps later nearby or in another function
more_records = .... #another list
more_records.sort(key=self.attr_sort(attrs=self.SortListB))

这将使用生成的 lambda 函数对列表进行排序object.attrA,然后object.attrB假设object具有与提供的字符串名称相对应的 getter。第二种情况将按object.attrCthen进行排序object.attrA

这还允许您潜在地公开向外的排序选择以供消费者、单元测试共享,或者让他们告诉您他们希望如何对 API 中的某些操作进行排序,只需给您一个列表,而不必将它们耦合到您的后端实现。

解决方案 5:

将列表列表转换为元组列表,然后按多个字段对元组进行排序。

 data=[[12, 'tall', 'blue', 1],[2, 'short', 'red', 9],[4, 'tall', 'blue', 13]]

 data=[tuple(x) for x in data]
 result = sorted(data, key = lambda x: (x[1], x[2]))
 print(result)

输出:

 [(2, 'short', 'red', 9), (12, 'tall', 'blue', 1), (4, 'tall', 'blue', 13)]

解决方案 6:

这里有一种方法:基本上,您重写排序函数以获取排序函数列表,每个排序函数比较要测试的属性,在每次排序测试中,您查看 cmp 函数是否返回非零值,如果是,则返回中断并发送返回值。您可以通过调用 Lambda 列表中的函数的 Lambda 来调用它。

它的优点是它只传递一次数据,而不是像其他方法那样先进行排序。另一个优点是它在原地排序,而 sorted 似乎会进行复制。

我用它来编写了一个排名函数,该函数对类列表进行排名,其中每个对象都属于一个组,并且具有评分函数,但您可以添加任何属性列表。请注意,虽然使用 lambda 调用 setter 的方式有点黑客,但与 lambda 并不类似。排名部分不适用于列表数组,但排序可以。

#First, here's  a pure list version
my_sortLambdaLst = [lambda x,y:cmp(x[0], y[0]), lambda x,y:cmp(x[1], y[1])]
def multi_attribute_sort(x,y):
    r = 0
    for l in my_sortLambdaLst:
        r = l(x,y)
        if r!=0: return r #keep looping till you see a difference
    return r

Lst = [(4, 2.0), (4, 0.01), (4, 0.9), (4, 0.999),(4, 0.2), (1, 2.0), (1, 0.01), (1, 0.9), (1, 0.999), (1, 0.2) ]
Lst.sort(lambda x,y:multi_attribute_sort(x,y)) #The Lambda of the Lambda
for rec in Lst: print str(rec)

以下是对对象列表进行排序的方法

class probe:
    def __init__(self, group, score):
        self.group = group
        self.score = score
        self.rank =-1
    def set_rank(self, r):
        self.rank = r
    def __str__(self):
        return '    '.join([str(self.group), str(self.score), str(self.rank)]) 


def RankLst(inLst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank)):
    #Inner function is the only way (I could think of) to pass the sortLambdaLst into a sort function
    def multi_attribute_sort(x,y):
        r = 0
        for l in sortLambdaLst:
            r = l(x,y)
            if r!=0: return r #keep looping till you see a difference
        return r

    inLst.sort(lambda x,y:multi_attribute_sort(x,y))
    #Now Rank your probes
    rank = 0
    last_group = group_lambda(inLst[0])
    for i in range(len(inLst)):
        rec = inLst[i]
        group = group_lambda(rec)
        if last_group == group: 
            rank+=1
        else:
            rank=1
            last_group = group
        SetRank_Lambda(inLst[i], rank) #This is pure evil!! The lambda purists are gnashing their teeth

Lst = [probe(4, 2.0), probe(4, 0.01), probe(4, 0.9), probe(4, 0.999), probe(4, 0.2), probe(1, 2.0), probe(1, 0.01), probe(1, 0.9), probe(1, 0.999), probe(1, 0.2) ]

RankLst(Lst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank))
print '    '.join(['group', 'score', 'rank']) 
for r in Lst: print r

解决方案 7:

列表之间有一个运算符 <,例如:

[12, 'tall', 'blue', 1] < [4, 'tall', 'blue', 13]

将给予

False

解决方案 8:

多重排序,可以指定每个属性的升序/降序

from operator import itemgetter, attrgetter
from functools import cmp_to_key


def multikeysort(items, *columns, attrs=True) -> list:
    """
    Perform a multiple column sort on a list of dictionaries or objects.
    Args:
        items (list): List of dictionaries or objects to be sorted.
        *columns: Columns to sort by, optionally preceded by a '-' for descending order.
        attrs (bool): True if items are objects, False if items are dictionaries.

    Returns:
        list: Sorted list of items.
    """
    getter = attrgetter if attrs else itemgetter

    def get_comparers():
        comparers = []

        for col in columns:
            col = col.strip()
            if col.startswith('-'):  # If descending, strip '-' and create a comparer with reverse order
                key = getter(col[1:])
                order = -1
            else:  # If ascending, use the column directly
                key = getter(col)
                order = 1

            comparers.append((key, order))
        return comparers

    def custom_compare(left, right):
        """Custom comparison function to handle multiple keys"""
        for fn, reverse in get_comparers():
            result = (fn(left) > fn(right)) - (fn(left) < fn(right))
            if result != 0:
                return result * reverse
        return 0

    return sorted(items, key=cmp_to_key(custom_compare))

使用/测试SORT by DESC('opens'), ASC('clicks')

def test_sort_objects(self):
    Customer = namedtuple('Customer', ['id', 'opens', 'clicks'])

    customer1 = Customer(id=1, opens=4, clicks=8)
    customer2 = Customer(id=2, opens=4, clicks=7)
    customer3 = Customer(id=2, opens=5, clicks=1)
    customers = [customer1, customer2, customer3]

    sorted_customers = multikeysort(customers, '-opens', 'clicks')
    exp_sorted_customers = [customer3, customer2, customer1]
    self.assertEqual(exp_sorted_customers, sorted_customers)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1048  
  在产品开发领域,如何提升产品交付质量一直是企业关注的焦点。集成产品开发(IPD)作为一种系统化的产品开发方法,通过跨职能团队的协同、流程的优化以及资源的整合,能够有效提升产品的交付质量。IPD培训作为推动这一方法落地的重要工具,不仅能够帮助团队理解IPD的核心原则,还能通过实践和案例学习,提升团队的执行力和协作效率。本...
IPD研发管理体系   0  
  在现代企业中,跨部门合作已成为项目成功的关键因素之一。随着业务复杂性的增加,单一部门难以独立完成复杂的项目任务,因此需要多个部门的协同努力。然而,跨部门合作往往面临沟通不畅、职责不清、资源冲突等挑战,这些问题如果得不到有效解决,将直接影响项目的进度和质量。在这种背景下,IPD(集成产品开发)项目流程图作为一种系统化的管...
华为IPD流程   0  
  在研发IPD(集成产品开发)流程中,跨部门协作是确保项目成功的关键因素之一。IPD流程强调从概念到市场的全生命周期管理,涉及市场、研发、制造、供应链等多个部门的协同工作。然而,由于各部门的目标、工作方式和优先级不同,跨部门协作往往面临沟通不畅、资源冲突、决策延迟等挑战。为了应对这些挑战,企业需要采取系统化的方法,优化跨...
IPD概念阶段   0  
  在项目管理的生命周期中,CDCP(Concept Development and Control Plan)阶段是项目从概念到实施的关键过渡期。这一阶段不仅需要明确项目的目标和范围,还需要确保项目团队能够灵活应对可能出现的变更和调整。变更管理在这一阶段尤为重要,因为任何未经控制的变更都可能对项目的进度、成本和质量产生深...
IPD流程中TR   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用