تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
الدوال lambda و map و filter في بيثون
#1
الدوال lambda و map و filter


يمكن استخدام بيثون في البرمجة الوظيفية أو في البرمجة الكائنية، والهدف من ذلك جعل بيثون سهلا وقويا في آن. سنتحدث في هذا الموضوع عن الدوال lambda و map و filter

الدوال lambda

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

كيف نكتب دالة lambda

نكتب الكلمة المفتاحية lambda متبوعة بوسيط او اكثر (هنا x) ثم النقطتان متبوعتان بالتعبير الذي نريد تنفيذه

كود :
lambda x: x**2 -1
ليس للدالة التي كتبناها اسم أي ليس لها مرجع يمكنني استخدامه لاستدعائها وبالتالي لا يمكننا استخدامها. كان يمكننا ربطها بمتغير مثلا ثم استخدامها كما نستخدم دالة عادية:

كود :
fx = lambda x: x**2 -1
fx                  # <function <lambda> at 0x7f90fc3f2c80>
fx(5)
لكن بما أننا اعطيناها اسما، فربما فقدت صفتها كدالة lambda واصبحت دالة عادية نوعا ما. لنر التطبيق العملي لدوال lambda.

سنعرف دالة عادية باسم image بسيطة للغاية تأخذ دالة f كوسيط:

كود :
def image(f):
   for x in range(10):
       print("f({}) = {}".format(x, f(x)))
لاستخدامها سنمرر لها دالة lambda كوسيط لكي نتجنب تعريف دالة ثانية:

كود :
image(lambda x: x**2 - 1)
لاحظ أنه كان يمكننا تعريف دالة ثانية وتمريرها كوسيط كما يلي وسنحصل على نفس النتائج:

كود :
def f(x):
   return x**2 - 1

image(f)
ربما لا نرى فارقا يذكر لكننا باستخدام lambda بسطنا الكود وجعلناه اقرب للفهم

الدوال map و filter

هما دالتان مدمجتان في بيثون مستخدمتان اساسا في البرمجة الوظيفية: map تتيح تطبيق دالة على كل عنصر من عناصر كائن تكراري iterable وترد لنا مكرِّرا (iterator) من نوع map:

كود :
m = map(f, range(10))
m                       # <map object at 0x7f90fc4164e0>
list(m)                 # [-1, 0, 3, 8, 15, 24, 35, 48, 63, 80]
كود :
m = map(lambda x: x**2 - 1, range(10))
list(m)                 # [-1, 0, 3, 8, 15, 24, 35, 48, 63, 80]
الدالة filter

تيح الدالة filter، كما يوضح اسمها، غربلة/تصفية عناصر كائن تكراري iterable حسب تعليمة فرز/انتقاء وترد لنا [b]مكرِّراiterator من نوع filter[/b]

كود :
f = filter (lambda x: x % 2 == 0, range(10))
f                       # <filter object at 0x7f90fc3e8f98>
list(f)                 # [0, 2, 4, 6, 8]
هذه الدوال ربما تذكرنا بمفهوم list comprehension

كود :
# map vs list comprehension
m = map(lambda x: x**2 - 1, range(10))
list(m)                 # [-1, 0, 3, 8, 15, 24, 35, 48, 63, 80]
m = [x**2 - 1 for x in range(10)]
print(m)                # [-1, 0, 3, 8, 15, 24, 35, 48, 63, 80]
كود :
# filter vs list comprehension
f = filter (lambda x: x % 2 == 0, range(10))
list(f)                 # [0, 2, 4, 6, 8]
f = [x for x in range(10) if x % 2 == 0]
print(f)                # [0, 2, 4, 6, 8]
كما ترى نستطيع الحصول على نفس النتائج بالضبط عبر list comprehension وهي الطريقة المفضلة في البرمجة البيثونية عوض map او filter، مع الملاحظة أن هاتين الدالتين لا تنتجان كائنا جديدا على خلاف الـlist comprehension التي تنتج قائمة جديدة حتى لو لم تكن بحاجة اليها.

نقطة اضافية ربما علينا أن نتذكرها، الا وهي أن ما تنتجه الدالتان map و filter هو [b]مكرِّر(iterator)، اي مؤشر لا نستطيع التنقل بواسطته الا مرة واحدة، فاذا رغبنا في اعادة استخدامه مرة اخرى علينا اعادة انشائه:[/b]

كود :
m = map(lambda x: x**2 - 1, range(10))
list(m)                 # [-1, 0, 3, 8, 15, 24, 35, 48, 63, 80]
list(m)                 # []
عندما حاولنا عرض القائمة من جديد وجدناها فارغة، على خلاف الـlist comprehension

بعض الاستخدامات البسيطة: استخراج العنصر الاكبر او الاصغر او المجموع (لاحظ انه لا يمكنك استخدام map سوى مرة واحدة):

كود :
# max
m = map(lambda x: x**2 - 1, range(10))
m_max = max(m)
m_max
# min
m = map(lambda x: x**2 - 1, range(10))
m_min = min(m)
m_min
# sum
m = map(lambda x: x**2 - 1, range(10))
m_sum = sum(m)
m_sum
لترتيب عناصر قائمة تتكون من صفوف، حيث يتوجب علينا أحيانا تحديد طريقة ترتيب الصفوف، مثلا لو كان لدينا قائمة تحتوي على صفوف الطول والعرض كما يلي:

كود :
mlist = [(43, 17), (42, 10), (46, 7), (55, 15)]
فاذا رغبنا في ترتيب القائمة بحسب العنصر الثاني (المؤشر 1) في كل صف، يمكننا استخدام دالة lambdaكما يلي:

كود :
mlist.sort(key = lambda x: x[1])
print(mlist)
ملاحظة: الوظيفة sort الخاصة بالقوائم تقوم باعادة الترتيب in place أي بدون نسخ وهي تعدل ترتيب عناصر القائمة نهائيا، فلو اردنا الاحتفاظ بالترتيب الاصلي أو اردنا اعادة ترتيب كائن تكراري (iterable) من نوع آخر غير القوائم علينا استخدام الدالة sorted التي ترد لنا قائمة مرتبة

كود :
mtuple = ((43, 17), (42, 10), (46, 7), (55, 15))
msorted = sorted(mtuple, key = lambda x:x[1])
print(msorted)          # a sorted list
tuple(msorted)          # transformed to tuple
print(mtuple)           # the original tuple
مراجع
راجع الدوال المدمجة في لغة بيثون: https://docs.python.org/3/library/functi...-functions

[b]وحول البرمجة الوظيفية راجع الرابط التالي: https://docs.python.org/3/howto/functional.html[/b]
ملاحظة أخيرة:
حاولت ترجمة المفردات التالية قدر المستطاع وربما وقعت في لبس. أرحب بكل الملاحظات المفيدة:
تكراري    =   iterable
مكرِّر   =   iterator
تكرار    =   iteration
الرد


التنقل السريع :


مستخدمين يتصفحوا هذا الموضوع: 1 ضيف