用Python中的自定义标准对复杂对象进行排序
#编程 #教程 #python #sorting

在大多数情况下,排序是一个简单的任务,但是有时数据有点复杂,而Python提供了处理这些方案的优雅方法。因此,我们将在本文中查看一个复杂的方案

对象结构

带有类定义

class Laptop:
    def __init__(self, cpu, ram, ssd) -> None:
    self.cpu = cpu
    self.ram = ram
    self.ssd = ssd

A = Laptop("Ryzen 7", 8,  256)
B = Laptop("Ryzen 5", 8,  512)
C = Laptop("Ryzen 7", 16, 128)
D = Laptop("Ryzen 5", 16, 128)

arr = [A,B,C,D]

作为列表项目

A = [ "Ryzen 7", 8, 256 ]
B = [ "Ryzen 5", 8, 512 ]
C = [ "Ryzen 7", 16, 128 ]
D = [ "Ryzen 5", 16, 128 ]

arr = [A,B,C,D]

目录

使用密钥参数排序

可以说,我们的优先级是按此顺序的,cpu > ram > ssd

# As class objects
arr.sort(key=lambda x:(x.cpu,x.ram, x.ssd), reverse=True)

# As list items
arr.sort(key=lambda x:(x[0], x[1], x[2]), reverse=True)

结果是,

Ryzen 7, 16, 128
Ryzen 7, 8, 256
Ryzen 5, 16, 128
Ryzen 5, 8, 512

对于更简单的情况,当您只有一个条件时,您不需要使用元组

arr.sort(key=lambda x:x.cpu, reverse=True)

操作员超载

让我们通过引入英特尔使场景更加复杂,

E = Laptop("Intel i7", 16, 512)

arr = [A,B,C,D,E]

如果我们不更改任何内容,结果将是

Ryzen 7, 16, 128
Ryzen 7, 8, 256
Ryzen 5, 16, 128
Ryzen 5, 8, 512
Intel i7, 16, 512
  • 可能不是我们想要的,我们以前取得了预期的结果

  • 为了示范,让我们以这种方式定义优先级,
    Ryzen 7 > Intel i7 > Ryzen5

这是使用操作员超载实现此结果的一种方法

class Laptop:
    def __init__(self, cpu, ram, ssd) -> None:
        self.cpu = cpu
        self.ram = ram
        self.ssd = ssd

    def __lt__(a, b):
        brand_a, model_a = a.cpu.split(" ")
        brand_b, model_b = b.cpu.split(" ")

        if brand_a == brand_b:
            if model_a != model_b:
                return model_a < model_b
        else:
            if brand_a == "Intel":
                return b.cpu == "Ryzen 7"
            elif brand_b == "Intel":
                return a.cpu == "Ryzen 5"

        if a.ram != b.ram:
            return a.ram < b.ram

        return a.ssd < b.ssd

在此功能中,返回0表示a较小,如果返回1,则b较小

定义“ <”操作员时,您可以通过简单地调用
进行排序

arr.sort(reverse=True)

比较器功能

from functools import cmp_to_key

def comparator(a, b):
    return a.ram - b.ram

arr.sort(key=cmp_to_key(comparator), reverse=True)

您可以使用比较器函数

编写类似复杂性的逻辑

但是,在这种方法中,返回-1或任何负数的a表示a,如果返回正数,则a比b小。如果返回0,则它们具有相同的优先级,并且不会交换

  • 使用比较器功能的好处是,您不超载类操作员,并且可以选择用于不同用例的多个比较器。
  • 如果您已经超载了“ <”运算符,但是在您的标准有点不同的情况下出现了一个场景,那么比较器函数就是您可能需要的

解决这个问题的更聪明的方法

使用字典来定义CPU模型的优先级,

mp = {
    "Ryzen 5"  : 0,
    "Intel i7" : 1,
    "Ryzen 7"  : 2
}

然后逻辑变得更简单,

def __lt__(a, b):
    if a.cpu != b.cpu:
        return mp[a.cpu] < mp[b.cpu]

    if a.ram != b.ram:
        return a.ram < b.ram

    return a.ssd < b.ssd

要使用比较器函数,只需用负(“ - ”)运算符替换少于(“ <”)操作员

您可能已经猜到了您可以在不使用操作员过载的情况下使其变得更简单

arr.sort(key=lambda x:(mp[x.cpu], x.ram, x.ssd),reverse=True)

这将是结果,

Ryzen 7, 16, 128
Ryzen 7, 8, 256
Intel i7, 16, 512
Ryzen 5, 16, 128
Ryzen 5, 8, 512

结论

所有三种方式可能都有其位置


上找到我 ð»Github
ðLinkedIn
Twitter