استخدام max وmin مع key في Python: أكبر عنصر في List of Dictionaries | بايثون بالمثال 8

استخدام max و min مع key في Python لاختيار أكبر أو أصغر عنصر حسب معيار مخصص

إذا كنت تعرف أن max() تعيد أكبر رقم وأن min() تعيد أصغر رقم، فقد وصلت إلى الخطوة التالية: ماذا لو كانت عناصر القائمة قواميس أو tuples أو نصوصًا، وتريد المقارنة حسب سعر أو درجة أو طول معيّن؟ هنا نستخدم المعامل key=.

في هذا المقال من بايثون العرب سنستخدم max() وmin() مع key لاختيار العنصر الكامل حسب معيار مخصص، مثل أعلى price في List of Dictionaries أو أعلى score أو أطول نص.

أما إذا كان هدفك فقط إيجاد أكبر وأصغر رقم عادي في قائمة، فراجع المقال المتخصص: إيجاد أكبر وأصغر رقم في قائمة Python.

{getToc} $title={محتوى المقال}

{alertInfo} الفكرة الأساسية: key لا تغيّر العنصر الذي تعيده max() أو min()؛ بل تحدد فقط القيمة التي ستستخدمها Python للمقارنة بين العناصر.

ما وظيفة key في max و min؟

الصيغة العامة هي:

max(items, key=function)
min(items, key=function)

تأخذ Python كل عنصر، تمرره إلى دالة key للحصول على قيمة المقارنة، ثم تعيد العنصر الأصلي صاحب أكبر أو أصغر قيمة.

فكرة المقارنة باستخدام key في max و min بدل مقارنة العنصر كاملًا

مثلًا، لاختيار أطول كلمة بدل الترتيب الأبجدي:

words = ["AI", "Python", "programming", "web"]

longest = max(words, key=len)
shortest = min(words, key=len)

print(longest)
print(shortest)
programming
AI

لاحظ أن key=len استخدمت طول كل كلمة للمقارنة، لكن max() أعادت الكلمة نفسها وليس رقم طولها.

أكبر عنصر في List of Dictionaries حسب price

هذه من أهم الحالات العملية. لنفترض أن لدينا منتجات، وكل منتج عبارة عن dict:

products = [
    {"name": "Laptop", "price": 1200},
    {"name": "Phone", "price": 800},
    {"name": "Tablet", "price": 450}
]

most_expensive = max(
    products,
    key=lambda item: item["price"]
)

print(most_expensive)
{'name': 'Laptop', 'price': 1200}

التعبير lambda item: item["price"] يقول لـPython: عند مقارنة كل قاموس، استخدم قيمة price. والنتيجة هي القاموس الكامل للمنتج الأعلى سعرًا.

مثال استخدام max و min مع lambda لاختيار عنصر من List of Dictionaries

أصغر عنصر حسب price

نستخدم نفس الفكرة مع min():

cheapest = min(
    products,
    key=lambda item: item["price"]
)

print(cheapest)
{'name': 'Tablet', 'price': 450}

إيجاد أعلى score في List of Dictionaries

لا يقتصر الأمر على الأسعار. إذا كانت لديك قائمة طلاب مثلًا:

students = [
    {"name": "Ali", "score": 88},
    {"name": "Sara", "score": 96},
    {"name": "Omar", "score": 91}
]

top_student = max(
    students,
    key=lambda student: student["score"]
)

print(top_student["name"])
print(top_student["score"])
Sara
96
{alertSuccess} إذا أردت العنصر الكامل صاحب أعلى قيمة، استخدم max(list, key=...). لا تنشئ قائمة منفصلة من القيم إلا إذا كنت تحتاج القيم نفسها لسبب آخر.

هل تريد العنصر الكامل أم أكبر قيمة فقط؟

هناك فرق مهم بين استخراج القيمة القصوى واستخراج العنصر الذي يحملها. إذا كتبت:

highest_price = max(
    item["price"]
    for item in products
)

print(highest_price)
1200

ستحصل على السعر فقط. أما max(products, key=lambda item: item["price"]) فتعيد قاموس المنتج كاملًا، وهذا أفضل عندما تحتاج الاسم والسعر وبقية بيانات العنصر.

إذا كان لديك Dictionary واحد بدل List of Dictionaries

إذا كانت البيانات بهذا الشكل {"Ali": 88, "Sara": 96} وتريد الاسم صاحب أعلى قيمة، يمكنك تمرير الدالة dict.get إلى key:

scores = {
    "Ali": 88,
    "Sara": 96,
    "Omar": 91
}

best_name = max(
    scores,
    key=scores.get
)

print(best_name)

هذه حالة مختلفة عن List of Dictionaries: هنا max() تمر على مفاتيح القاموس، وscores.get تعطيها القيمة المقابلة لكل مفتاح للمقارنة.

استخدام itemgetter بدل lambda

عندما يكون معيار المقارنة مجرد مفتاح داخل Dictionary أو موضع داخل Tuple، يمكنك استخدام operator.itemgetter() بدل كتابة lambda في كل مرة.

from operator import itemgetter

most_expensive = max(
    products,
    key=itemgetter("price")
)

print(most_expensive)

للمبتدئ، lambda غالبًا أوضح لأنها تعرض منطق المقارنة أمامك مباشرة. أما itemgetter() فهي بديل مختصر ومفيد عندما يتكرر نفس النمط.

استخدام max مع Tuple حسب العنصر الثاني

إذا كانت البيانات tuples مثل (name, score) وتريد المقارنة حسب الدرجة، فاستخدم العنصر ذي الفهرس 1:

results = [
    ("Ali", 78),
    ("Sara", 95),
    ("Omar", 86)
]

best = max(
    results,
    key=lambda item: item[1]
)

print(best)
('Sara', 95)

ما الفرق بين max مع key وبين sorted؟

إذا كنت تحتاج عنصرًا واحدًا فقط هو الأكبر أو الأصغر حسب معيار، استخدم max() أو min(). أما sorted() فتستخدمها عندما تحتاج ترتيب جميع العناصر.

الحاجة الأداة المناسبة مثال
أعلى عنصر حسب score max() max(students, key=lambda x: x["score"])
أقل عنصر حسب price min() min(products, key=lambda x: x["price"])
ترتيب كل العناصر حسب score sorted() sorted(students, key=lambda x: x["score"])

ماذا يحدث عند تساوي أكبر قيمة؟

إذا كان أكثر من عنصر يملك نفس قيمة key القصوى، فإن max() تعيد أول عنصر صادفته من العناصر المتساوية. وينطبق المبدأ نفسه على min().

players = [
    {"name": "Ali", "score": 95},
    {"name": "Sara", "score": 95},
    {"name": "Omar", "score": 88}
]

winner = max(
    players,
    key=lambda player: player["score"]
)

print(winner["name"])
Ali

إذا كنت تريد جميع العناصر المتساوية

استخرج القيمة القصوى أولًا، ثم رشّح كل العناصر التي تحملها:

best_score = max(
    players,
    key=lambda player: player["score"]
)["score"]

leaders = [
    player
    for player in players
    if player["score"] == best_score
]

print(leaders)

قاعدة كسر التعادل بمعيار ثانٍ

يمكن أن تعيد دالة key tuple. تقارن Python العنصر الأول، ثم تستخدم الثاني إذا حدث تعادل:

best_player = max(
    players,
    key=lambda player: (
        player["score"],
        player["name"]
    )
)

استخدم معيارًا ثانيًا فقط عندما يكون له معنى حقيقي في بياناتك، لا لمجرد التخلص من التعادل.

ماذا لو كانت القائمة فارغة؟ استخدم default

استدعاء max([]) أو min([]) بدون عناصر يرفع ValueError. عند تمرير iterable واحد يمكنك تحديد قيمة default تعاد عند الفراغ:

products = []

result = max(
    products,
    key=lambda item: item["price"],
    default=None
)

if result is None:
    print("لا توجد منتجات")
{alertWarning} استخدم default بقيمة تستطيع تمييزها بوضوح عن النتائج الطبيعية، مثل None عندما لا تكون None عنصرًا صالحًا في البيانات.

خطأ شائع: المفتاح غير موجود في بعض القواميس

هذا الكود يفترض أن كل عنصر يحتوي على price:

most_expensive = max(
    products,
    key=lambda item: item["price"]
)

إذا كان أحد القواميس بلا مفتاح price فسيظهر KeyError. الأفضل أن تكون بنية البيانات متسقة. ويمكن استخدام item.get("price", ...) فقط عندما تحدد بوضوح ما القيمة الافتراضية الصحيحة في مشروعك.

متى لا تحتاج إلى key؟

إذا كانت القائمة تحتوي على أرقام مباشرة وتريد أعلى أو أقل رقم فقط، فلا حاجة إلى key:

numbers = [15, 8, 22, 4]

print(max(numbers))
print(min(numbers))
شرح إيجاد أكبر وأصغر رقم في قائمة Python باستخدام for loop خطوة بخطوة

شرح إيجاد أكبر وأصغر رقم عادي والحل اليدوي باستخدام for loop موجود بالفعل في المقال الأساسي المتخصص، لذلك لا نكرره هنا.

جدول سريع لاختيار key المناسب

نوع البيانات المطلوب key
نصوص أطول نص key=len
List of Dictionaries أعلى سعر key=lambda x: x["price"]
List of Dictionaries أعلى درجة key=lambda x: x["score"]
Tuples أعلى قيمة في العنصر الثاني key=lambda x: x[1]
Dictionary / Tuple متكرر استخراج حقل مباشر itemgetter(...)
ملخص استخدام max و min مع key و lambda و itemgetter في Python

أسئلة شائعة عن max و min مع key

ما معنى key في max و min؟

هي دالة تأخذ كل عنصر وتعيد قيمة تستخدمها Python للمقارنة. النتيجة النهائية تبقى العنصر الأصلي.

كيف أجد أكبر Dictionary حسب قيمة معينة؟

مرر قائمة القواميس إلى max() واستخدم مثلًا key=lambda x: x["price"] للمقارنة حسب السعر.

هل lambda إلزامية مع key؟

لا. يمكنك تمرير دالة موجودة مثل len، أو دالة عادية كتبتها أنت، أو أدوات مثل operator.itemgetter().

ماذا يعيد max عند تساوي قيم key؟

يعيد أول عنصر صادفه من العناصر التي تملك القيمة القصوى نفسها. وإذا أردت كل العناصر المتساوية، استخرج القيمة القصوى ثم رشّح العناصر التي تحملها.

كيف أستخدم max مع قائمة فارغة؟

استخدم default عند تمرير iterable واحد، مثل max(items, key=..., default=None).

روابط مفيدة

الخلاصة

عندما تكون العناصر أرقامًا مباشرة، يكفي غالبًا max(numbers) وmin(numbers). أما عندما تكون البيانات مركبة، فإن key= هي الأداة التي تحدد بأي قيمة تتم المقارنة.

مع List of Dictionaries يمكنك المقارنة حسب price أو score باستخدام lambda أو itemgetter(). ومع النصوص تستطيع استخدام key=len، ومع tuples تستطيع المقارنة حسب موضع محدد.

{alertSuccess} القاعدة العملية: استخدم max(..., key=...) أو min(..., key=...) عندما تريد إرجاع العنصر الكامل، لكن المقارنة يجب أن تتم حسب خاصية محددة داخله.

إرسال تعليق

أحدث أقدم