تابع filter در پایتون یک تابع پیشساخته (built-in) است که عناصر یک ایتریبل (iterable) را بر اساس یک شرط مشخص فیلتر میکند و تنها عناصری را که تابع شرط برای آنها مقدار True برمیگرداند، نگه میدارد. این تابع یکی از ابزارهای اصلی برنامهنویسی تابعی در پایتون است.
فهرست مطالب:
سینتکس تابع filter
سینتکس کلی تابع filter به صورت زیر است:
filter(function, iterable)
پارامترها یا آرگومانهای این سینتکس عبارتند از:
- آرگومان
functionیک تابع است که به ازای هر عنصر ازiterableفراخوانی میشود و باید مقدار True یا False (یا معادلهای آنها) برگرداند. اگر مقدار None وارد شود، پایتون از خود عناصر به عنوان شرط استفاده میکند و عناصری که مقدار falsy دارند را حذف میکند. - آرگومان
iterableهر شیء قابل پیمایش مانند لیست، تاپل، رنج، مجموعه یا استرینگ است که میخواهیم روی عناصر آن فیلتر اعمال کنیم.
مقدار بازگشتی تابع filter یک آبجکت filter است، نه یک لیست! این آبجکت یک iterator است که عناصر واجد شرط را به صورت تنبل (lazy) تولید میکند. برای دریافت نتیجه به صورت لیست یا تاپل باید آن را با تابع ()list یا ()tuple تبدیل کنید.
کاربردهای تابع filter
سادهترین مثال از کاربرد این تابع میتواند حالت زیر باشد:
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> even = list(filter(lambda x: x % 2 == 0, numbers))
>>> even
[2, 4, 6, 8, 10]
در این مثال از توابع لاندا برای بررسی زوج بودن اعضای لیست numbers استفاده شده است. برای آن دسته از اعضای لیست numbers که حاصل تقسیم عضو بر عدد ۲ مساوی با ۰ باشد (زوج باشند)، مقدار بازگشتی تابع لاندا True است.
یا میتوان با پاس دادن None به عنوان تابع، مقادیر falsy را از ایتریبل حذف کرد:
>>> data = [0, 1, "", "Hello", None, False, True, [], [1, 2]]
>>> result = list(filter(None, data))
>>> result
[1, 'Hello', True, [1, 2]]
در این حالت تابع filter تمام مقادیری که در پایتون معادل False هستند را حذف میکند.
یادآوری: مقادیری مانند عدد 0، استرینگ خالی، بولین None، False و لیست خالی، مثالهایی از مقادیر falsy هستند.
رایجترین کاربردهای تابع filter عبارتند از:
- حذف مقادیر None یا falsy از یک لیست،
- فیلتر کردن دادهها بر اساس یک شرط مشخص،
- پردازش و پاکسازی دادههای ورودی قبل از پردازش اصلی،
- ترکیب با تابع
()mapبرای پیادهسازی پایپلاینهای پردازش داده.
استفاده از تابع با تعریف جداگانه: به جای lambda، میتوانید یک تابع مستقل تعریف کرده و آن را به filter بدهید. این روش کد خواناتری تولید میکند:
def is_positive(number):
return number > 0
numbers = [-3, -1, 0, 2, 5, -7, 8]
positives = list(filter(is_positive, numbers))
print(positives)
# output: [2, 5, 8]
فیلتر کردن دیکشنریها: یکی از کاربردهای رایج filter پردازش لیستی از دیکشنریهاست؛ برای مثال فیلتر کردن محصولات موجود در انبار:
products = [
{"name": "laptop", "price": 45000000, "in_stock": True},
{"name": "mouse", "price": 850000, "in_stock": False},
{"name": "keyboard", "price": 1200000, "in_stock": True},
{"name": "monitor", "price": 12000000, "in_stock": False},
]
available = list(filter(lambda p: p["in_stock"], products))
for p in available:
print(p["name"])
# output:
laptop
keyboard
مثال واقعی از تابع filter
در یک سناریوی فرضی، شما یک سیستم ثبتنام دارید و میخواهید از میان کاربران ثبتنام شده، فقط کاربرانی را که هم ایمیل معتبر دارند و هم سن آنها بالای ۱۸ سال است، انتخاب کنید:
users = [
{"name": "Ali", "age": 25, "email": "ali@example.com"},
{"name": "Sara", "age": 16, "email": "sara@example.com"},
{"name": "Reza", "age": 30, "email": ""},
{"name": "Maryam", "age": 22, "email": "maryam@example.com"},
{"name": "Shayan", "age": 15, "email": "shayan@example.com"},
]
def is_valid_user(user):
return user["age"] >= 18 and bool(user["email"])
valid_users = list(filter(is_valid_user, users))
for user in valid_users:
print(f"{user['name']} — {user['email']}")
در این مثال، تابع is_valid_user دو شرط را همزمان بررسی میکند و filter تنها کاربرانی را که هر دو شرط را دارند به خروجی میفرستد:
Ali — ali@example.com
Maryam — maryam@example.com
تفاوت تابع filter با list comprehension
هر دو روش نتیجه یکسانی تولید میکنند، اما در نحوه استفاده تفاوت دارند:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# using lambda & filter
evens_filter = list(filter(lambda x: x % 2 == 0, numbers))
# using list comprehension
evens_comp = [x for x in numbers if x % 2 == 0]
print(evens_filter) # output: [2, 4, 6, 8, 10]
print(evens_comp) # output: [2, 4, 6, 8, 10]
به طور کلی، list comprehension در پایتون خواناتر و پایتونیکتر (Pythonic) است و برای اکثر موارد ساده ترجیح داده میشود. اما تابع filter زمانی مفیدتر است که:
- تابع شرط از پیش تعریف شده باشد و بخواهید آن را مستقیماً پاس دهید،
- با دادههای بسیار بزرگ کار کنید و به رفتار تنبل iterator نیاز داشته باشید،
- کد را در قالب یک پایپلاین تابعی با
()mapو()reduceترکیب کنید.
ترکیب filter با map
یکی از الگوهای رایج در برنامهنویسی تابعی، ترکیب filter و map در یک پایپلاین است:
numbers = [-5, -3, -1, 2, 4, 6, 8]
result = list(map(lambda x: x ** 2, filter(lambda x: x > 0, numbers)))
print(result)
# output: [4, 16, 36, 64]
این کد، ابتدا اعداد مثبت را فیلتر میکند، سپس مربع آنها را محاسبه میکند.
سوالات متداول
-
مقدار بازگشتی تابع filter چیست؟
تابع filter یک آبجکت از نوع filter برمیگرداند که یک iterator است، نه یک لیست. برای تبدیل آن به لیست باید از تابع
استفاده کنید.()list -
اگر None را به عنوان تابع به filter بدهم چه اتفاقی میافتد؟
در این حالت پایتون از خود عناصر به عنوان شرط استفاده میکند. عناصری که مقدار falsy دارند (مانند 0، “”, None، False، []) حذف میشوند و بقیه نگه داشته میشوند.
-
تفاوت filter و map چیست؟
تابع filter عناصری را که شرط آنها True است نگه میدارد و بقیه را حذف میکند؛ بنابراین تعداد عناصر خروجی کمتر یا مساوی ورودی است. تابع map اما یک تابع را روی تمام عناصر اعمال میکند و همیشه به تعداد عناصر ورودی، خروجی تولید میکند.
-
آیا filter با تاپل و مجموعه هم کار میکند؟
بله، filter با هر ایتریبلی کار میکند. اما مقدار بازگشتی آن همیشه یک آبجکت filter است.
-
کدام سریعتر است: filter یا list comprehension؟
در اکثر موارد عملکرد آنها بسیار نزدیک است. تابع filter با توابع پیشساخته (بدون lambda) میتواند کمی سریعتر باشد، اما list comprehension در اکثر سناریوها خواناتر و پایتونیکتر محسوب میشود.
جهت کسب اطلاعات بیشتر میتوانید به مستندات رسمی پایتون برای تابع filter مراجعه کنید.