تا میتونید داخل پایتون از لوپ استفاده نکنید، بجای لوپ از این موارد استفاده کنید…

آشنایی با map، Filterو reduce در پایتون
آشنایی با map، Filterو reduce در پایتون
زمان مطالعه: 4 دقیقه

با سلام و درود، به مطلب خوب داخل medium داشتم میخوندم و حیفم اومد اینجا به اشتراک نزارم. همراهم باشید 🙂

همون طور که می دونید loop جزو فانکشن های پرهزینه پایتون محسوب میشه (البته تو همه زبان های برنامه نویسی expensive هست) و اگر با تعداد ردیف های زیادی لوپ بزنید عملا جُرم انجام دادید :))

در ادامه به معرفی مواردی می پردازیم که میشه بجای لوپ در پایتون از آنها استفاده کرد.

فانکشن های زیر را بررسی خواهیم کرد:

  • Map
  • Filter
  • Reduce

اگر قبلا هم در مورد این فانکشن ها شنیدید، ارزش داره مجدد از مطلب رو بخونید و اطلاعاتتون رو مجدد تازه کنید.

قبل از شروع و معرفی فانکشن های فوق، نگاهی سریع به فانکشن lambda میندازیم:

خیلی خوبه که با لامبدا – Lambda آشنا باشید:

لامبدا مشابه یا جایگزینی برای regular function ها محسوب میشه، میتونید داخل یه خط کد اون رو تعریف کنید و درنتیجه زمان کمتر و فضای کمتری از کد رو اشغال می کنه. برای مثال به کد زیر نگاه بیاندازید:

def multiply_by_2(x):
    x*2

lambda x: x*2

۱- آشنایی با Map در پایتون :

از فانکشن map میتونیم روی هر مقدار از object تکرارپذیری (iterable) استفاده کنیم.

سینتکس آن به شرح زیر است:

map(function, iterable) 

حال بیاید در عمل با آن آشنا شویم.

فرض کنید ما میخواهیم توان دوم اعدادی داخل یک لیست (شامل اشیای تکرارپذیر) را بگیریم. ما ابتدا فانکشن توان دو را برای بدست آوردن توان دو عدد میسازیم:

def square(x):
    return x*x

حال ما از map برای اعمال کردن فانکشن square() روی لیستی از اعداد وارد شده استفاده می کنیم:

input_list = [2, 3, 4, 5, 6]

# Without lambda 
result = map(square, input_list)

# Using lambda function 
result = map(lambda x: x*x, input_list)

# converting the numbers into a list
list(result)# Output: [4, 9, 16, 25, 36]

۲- آشنایی با Filter در پایتون :

به طور شهودی، تابع فیلتر برای فیلتر کردن مقادیر از یک شی قابل تکرار (لیست، تاپل، مجموعه و غیره) استفاده می‌شود. شرایط فیلتر در داخل یک تابع تنظیم می شود که به عنوان آرگومان به تابع فیلتر ارسال می شود.

سینتکس :

filter(function, iterable)

بیاید به صورت عملی به تابع filter در پایتون بپردازیم:

میخواهیم از فانکشن فیلتر برای فیلتر کردن اعداد زیر ۱۰ استفاده کنیم.

def less_than_10(x):
    if x < 10:
        return x 

حال ار فانکشن فیلتر برای اعمال کردن فانکشن less_than_10() روی لیستی از مقادیر استفاده می کنیم:

input_list = [2, 3, 4, 5, 10, 12, 14]

# Without lambda
list(filter(less_than_10, input_list))

# using lambda function 
list(filter(lambda x: x < 10, input_list))

# Output: [2, 3, 4, 5]

۳- آشنایی با Reduce در پایتون:

فانکشن reduceیه مقدار متفاوت از فانکشن های map و filter می باشد. این تابع به صورت تکراری روی تمامی مقادیر اشیاء تکرار پذیر اعمال می شود و تنها یک مقدار بر می گرداند.

برای درک بهتر بیاید از یک تصویر استفاده کنیم:

در مثال زیر لیستی از اعداد با اعمال کردن فانکشن اضافه کردن، کاهش یافته اند. خروجی نهایی جمع تمامی اعداد لیست یعنی ۱۵ می باشد.

سینتکس فانکشن reduce:

reduce(func, iterable)

حال بیاید ببینیم در عمل فانکشن reduce به چه صورت کار می کند:

ابتدا فانکشن addition()را برای جمع کردن دو عدد ایجاد می کنیم:

def addition(x,y):
    return x + y

در ادامه برای گرفتن جمع تمامی اعداد لیست، این فانکشن اضافه کردن addition() را به عنوان آرگومان به فانکشن reduceمی دهیم.

from functools import reduceinput_list = [1, 2, 3, 4, 5]

# Without Lambda function
reduce(addition, input_list))

# With Lambda function
reduce(lambda x,y: x+y, input_list))

# Output: 15

نکته خیلی مهم مربوط به performance برای استفاده از reduce در پایتون:

اگر امکان استفاده زا توابع مستقیم وجود داره از اونها استفاده کنید و از reduce استفاده نکنید. توابعی مثل sum(), all(), any(), max(), min(), len(), math.prod() و غیره. استفاده از این توابع سرعت اجرای کد را خیلی بیشتر می کند.

مثال زیر از سایت RealPython را مشاهده کنید:

>>> from functools import reduce
>>> from timeit import timeit

>>> # Using a user-defined function
>>> def add(a, b):
...     return a + b
...
>>> use_add = "functools.reduce(add, range(100))"
>>> timeit(use_add, "import functools", globals={"add": add})
13.443158069014316

>>> # Using a lambda expression
>>> use_lambda = "functools.reduce(lambda x, y: x + y, range(100))"
>>> timeit(use_lambda, "import functools")
11.998800784000196

>>> # Using operator.add()
>>> use_operator_add = "functools.reduce(operator.add, range(100))"
>>> timeit(use_operator_add, "import functools, operator")
5.183870767941698

>>> # Using sum()
>>> timeit("sum(range(100))", globals={"sum": sum})
1.1643308430211619

همونطور که در کد بالا ملاحظه می کنید، تفاوت بسیار فاحش می باشد.

مقایسه map و loop در پایتون:

مثال و نتایج زیر از سایت geeksforgeeks استفاده شده است، فرض کنید مثال زیر را داریم:

# function to square a given number
def squareNum (a) :
    return a * a
  
  
listt = [0, -1, 3, 4.5, 99, .08]
  
# using 'map' to call the function
# 'squareNum' for all the elements
# of 'listt'
x = map(squareNum, listt)
  
# map function returns a map
# object at this particular 
# location
print(x) 
  
# convert map to list
print(list(x)) 
  
  
# alternate way to square all
# elements of 'listt' using
# 'for loop'
  
for i in listt :
    square = i * i
    print(square)

نتایج map و loop به صورت زیر می باشد که نشان میدهد map برنده این رقابت بوده است:

نتایج استفاده از loop
نتایج استفاده از map