برنامه نویسی

مرتب سازی اشیاء پیچیده با معیارهای سفارشی در پایتون

در بیشتر موارد، مرتب‌سازی کار ساده‌ای است، اما مواردی وجود دارد که داده‌ها کمی پیچیده هستند و پایتون روشی زیبا برای مدیریت آن سناریوها ارائه می‌دهد. بنابراین ما در این مقاله به یک سناریوی پیچیده نگاه خواهیم کرد

ساختار شی

با تعریف کلاس

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 > Ryzen 5 که توسط عملگر “<" رشته انجام می شود

  • برای نشان دادن، اجازه دهید تقدم را اینگونه تعریف کنیم،
    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 کوچکتر است، اگر عدد مثبت برگردانده شود از 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
🔘 لینکدین
توییتر

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا