الاستخدام العملي للقواميس
لنستخدم القواميس في مشكلة واقعية. تخيل أنك تبني متجرًا إلكترونيًا، وتحفظ أسعار المنتجات في قاموس:
prices = {'apple': 2, 'box': 5, 'cat': 100, 'dog': 100}
هذا يوضح سبب كون البحث في القاموس قائمًا على المفاتيح لا القيم. ماذا يمكن أن تعني prices[100]؟ هل النتيجة 'dog' أم 'cat' أم الاثنتان؟ يمكن أن تتكرر القيمة في القاموس مرات كثيرة.
أما المفاتيح فيجب أن تكون فريدة. تخيل مثلًا:
prices = {'apple': 2, 'apple': 3}
كم سعر التفاحة؟ نعرف أننا سنكتب prices['apple']، لكن هل القيمة 2 أم 3؟ منطقيًا يجب أن يكون هناك سعر واحد تحت المفتاح نفسه، ولذلك لا يمكن الاعتماد على مفاتيح مكررة لتمثيل قيمتين مختلفتين.
لدينا الآن متجر عادي، وعملاء لديهم قوائم مشتريات مثل ['apple', 'box', 'cat']. نريد حساب السعر الإجمالي بأنفسنا.
أكمل الدالة التالية، وخصوصًا السطر price = ...:
def total_cost(cart, prices):
result = 0
for item in cart:
price = ...
result += price
return result
check_result(
total_cost(
['apple', 'box', 'cat'],
{'apple': 2, 'box': 5, 'cat': 100, 'dog': 100},
),
107,
)
تذكّر أن prices قاموس، وأن العناصر الموجودة في cart هي المفاتيح التي تحتاجها للحصول على الأسعار.
تذكر أن
pricesis a dictionary.To access a value in a dictionary, you need a key.
The keys for
pricesare the items in thecart.
ممتاز! نشرت المتجر وبدأت تتخيل الأرباح، ثم جاء عميل يريد شراء خمسة ملايين كلب... وصندوقين ليضعها فيهما.
الموقع يستطيع تمثيل شراء العنصر نفسه عدة مرات بتكراره داخل cart، مثل ['box', 'box']، لكن هذا غير عملي عندما تكون الكمية ضخمة. لذلك سنفصل نوع العنصر عن الكمية.
هذا الكود الجديد يحتاج إلى إكمال:
def total_cost(cart, quantities, prices):
result = 0
for item in cart:
price = ...
quantity = ...
result += price * quantity
return result
check_result(
total_cost(
['dog', 'box'],
{'dog': 5000000, 'box': 2},
{'apple': 2, 'box': 5, 'cat': 100, 'dog': 100},
),
500000010,
)
أضفنا معاملًا اسمه quantities. ما زالت cart قائمة من النصوص، لكن من دون تكرار. أما quantities فهو قاموس مفاتيحه هي العناصر الموجودة في cart، وقيمة كل مفتاح هي الكمية المطلوبة من ذلك العنصر.
استخدم المفتاح نفسه item للوصول إلى السعر في prices والكمية في quantities.
تذكر أن the keys for
pricesandquantitiesare the same.This is very similar to the previous exercise, we're just practicing.
priceshould be a value fromprices, and similarly forquantity.What key should be used to obtain each value?
جيد! لكن ربما لاحظت شيئًا غير مريح: لماذا نكتب 'dog' و'box' في cart ثم نكررهما كمفاتيح في quantities؟ في الجزء التالي سنتعلم المرور مباشرة على مفاتيح القاموس حتى نستطيع الاستغناء عن cart.
قبل ذلك، لنتدرب أكثر.
تعاملنا سابقًا مع تحويل سلسلة DNA إلى سلسلة مقابلة بتبديل كل نوكليوتيد بما يطابقه. هذه نسخة من الفكرة داخل دالة؛ تستبدل كل حرف في string بحرف آخر:
def substitute(string):
result = ''
for char in string:
if char == 'A':
char = 'T'
elif char == 'T':
char = 'A'
elif char == 'G':
char = 'C'
elif char == 'C':
char = 'G'
result += char
return result
original = 'AGTAGCGTCCTTAGTTACAGGATGGCTTAT'
expected = 'TCATCGCAGGAATCAATGTCCTACCGAATA'
check_result(substitute(original), expected)
يمكننا الآن استخدام قاموس لجعل الكود السابق أقصر وأكثر عمومية.
أضف إلى الدالة substitute معاملًا ثانيًا اسمه d وهو قاموس. مفاتيح d تمثل الأحرف التي قد تظهر في string، وقيمة كل مفتاح هي الحرف الذي يجب أن يحل مكانه. مثلًا الزوج 'A': 'T' يعني استبدال 'A' بـ'T':
def substitute(string, d):
...
original = 'AGTAGCGTCCTTAGTTACAGGATGGCTTAT'
expected = 'TCATCGCAGGAATCAATGTCCTACCGAATA'
check_result(substitute(original, {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C'}), expected)
يجب أن تعمل هذه النسخة لأي مدخلات تكون فيها كل أحرف string مفاتيح موجودة في d. لم تعد هناك حاجة إلى سلسلة طويلة من if وelif: أثناء المرور على أحرف النص، استخدم الحرف نفسه كمفتاح للحصول على البديل المناسب من القاموس وابنِ النص الناتج.
This is still very similar to the previous exercises, but with strings instead of numbers.
You just have to think about the keys and values of
d.You need to obtain the correct values to build up a string to return.
You can basically replace the whole
if/elifchain with a single line.That line simply needs to use
dto get the correct value.تذكر أن the keys of
dare the characters instring.
رائع! يمكن استخدام الدالة نفسها أيضًا لتشفير رسائل بسيطة وفك تشفيرها:
def substitute(string, d):
result = ""
for letter in string:
result += d[letter]
return result
plaintext = 'helloworld'
encrypted = 'qpeefifmez'
letters = {'h': 'q', 'e': 'p', 'l': 'e', 'o': 'f', 'w': 'i', 'r': 'm', 'd': 'z'}
reverse = {'q': 'h', 'p': 'e', 'e': 'l', 'f': 'o', 'i': 'w', 'm': 'r', 'z': 'd'}
check_result(substitute(plaintext, letters), encrypted)
check_result(substitute(encrypted, reverse), plaintext)
الدالة نفسها تعمل في الاتجاهين؛ كل ما نفعله هو تمرير قاموس مختلف.
القاموسان متشابهان جدًا، لكننا نعكس المفتاح والقيمة في كل زوج. عند التشفير نستبدل e بـp، وعند فك التشفير نعيد p إلى e.
لاحظ أن 'e' تظهر كمفتاح وكقيمة داخل letters.
عندما نكتب letters['e'] فنحن نسأل عن 'e' بصفتها مفتاحًا، ولذلك نحصل على 'p'. ولا نستطيع سؤال القاموس نفسه مباشرة عن المفتاح الذي ترتبط به القيمة 'e'. لكن في هذا المثال لدينا القاموس العكسي؛ فـreverse['e'] تعطي 'l'، بينما letters['l'] تعيد 'e' مرة أخرى.
قريبًا ستكتب دالة تنشئ القاموس العكسي تلقائيًا، أي شيئًا مثل:
reverse = swap_keys_values(letters)