آموزش لیست کامپریهنشن در پایتون با مثال

یکی از قابلیت‌های کاربردی و جذاب python بحث List Comprehension است. این ساختار به ما امکان می‌دهد تا بدون نیاز به حلقه‌های طولانی و پیچیده، لیست‌های جدیدی را به‌سرعت ایجاد کنیم. در این آموزش با نحوه استفاده و کاربردهای List Comprehension در پایتون آشنا شده و با مثال‌های واقعی از آن‌ها استفاده می‌کنیم.

ممکن است لیست کامپریهنشن را در فارسی به نام «خلاصه‌سازی لیست» هم بشنوید؛ اما معمولاً همان List Comprehension گفته می‌شود. این ساختار، روشی ساده و کوتاه برای ایجاد لیست‌های جدید بر اساس لیست‌های موجود است.

برای مثال، فرض کنید می‌خواهیم مقادیر یک لیست از اعداد را دو برابر کرده و در لیست جدیدی ذخیره کنیم. روش مرسوم استفاده از حلقه for است؛ اما با List Comprehension پایتون می‌توان آن را در یک خط و به‌طور کوتاه‌تر انجام داد.

List Comprehension ساده در پایتون

مثال بالا را در نظر بگیرید. لیستی از اعداد به نام numbers داریم و می‌خواهیم مقادیر آن‌ها را دو برابر کرده و در یک لیست جدید قرار دهیم.

اولین روشی به ذهنمان می‌رسید، استفاده از حلقه در پایتون است. این‌گونه که با یک for روی اعضای لیست حرکت کرده، دو برابر شده‌ی هر عضو را درون لیست جدید می‌ریزیم. چیزی شبیه به کد زیر:

numbers = [1, 3, 4, 5, 9]
doubled_numbers = []

for num in numbers:
    doubled_numbers.append(num * 2)

قطعه کد بالا را با روش لیست کامپریهنشن می‌توان به شکل زیر نوشت:

numbers = [1, 3, 4, 5, 9]
doubled_numbers = [num * 2 for num in numbers]

List Comprehension در پایتون ساختار ساده و خوانایی دارد. با این حال بهتر است برای اولین بار، آن را کمی توضیح دهم. ابتدا این دو کد را با هم مقایسه کنید.

برای نوشتن حلقه، از for num in numbers جهت حرکت روی تمام اعضای لیست numbers استفاده کرده‌ایم. همچنین مقداری که در لیست نهایی (doubled_numbers) قرار می‌گیرد برابر num * 2 است.

مشابه عکس زیر، در بخش اول comprehension مشخص می‌کنیم که چه مقداری باید درون لیست جدید قرار بگیرد. در بخش دوم نیز مشخص می‌کنیم که این مقدار جدید بر اساس اعضای کدام لیست ایجاد شود. یعنی num * 2 مقداری است که باید به‌عنوان هر یک از اعضا در لیست جدید قرار بگیرد و for num in numbers مشخص می‌کند که متغیر num از اعضای کدام لیست خوانده شود.

مثال جالب از خلاصه‌سازی لیست

فرض کنید لیستی از رشته‌ها داریم که می‌خواهیم حروف اول آن‌ها را به‌صورت Upper (حروف بزرگ) تغییر داده و در لیست جدیدی قرار دهیم. با استفاده از حلقه، چیزی شبیه به کد زیر را داریم:

words = ["python", "list", "sabzdanesh", "tutorial"]
uppercase_words = []

for word in words:
    uppercase_words.append(word.upper())

با متد upper() در جلسهٔ آموزش رشته در پایتون آشنا شدیم. این متد حرف اول رشته را به حرف بزرگ تغییر می‌دهد.

ساده شده‌ی کد بالا با استفاده از List Comprehension در پایتون به‌صورت زیر است:

words = ["python", "list", "sabzdanesh", "tutorial"]
uppercase_words = [word.uppet() for word in words]

مقداری که باید به‌عنوان اعضای لیست جدید تعریف شوند می‌توانند هیچ ارتباطی با اعضای لیست قبلی نداشته باشند! برای مثال، در قطعه کد زیر، به ازای هر یک از اعضای لیست words، صرفاً یک کاراکتر '*' قرار می‌دهم:

words = ["python", "list", "sabzdanesh", "tutorial"]
example = ['*' for word in words]

لیست خروجی این قطعه کد چیزی شبیه به لیست تصویر زیر می‌شود. هر چند که ممکن است کاربرد چنین چیزی در این مثال واضح نباشد، اما خوب است بدانید که بنا به نیازتان می‌توانید یک مقدار ثابت به‌عنوان اعضای لیست جدید قرار دهید.

خروجی مقدار ثابت به ازای اعضای لیست
خروجی مقدار ثابت به ازای اعضای لیست

در List Comprehension ساده پایتون، ابتدا می‌گوییم مقداری که باید به‌عنوان عضو جدید در لیست قرار بگیرید چیست و سپس حلقهٔ موردنظر را برای حرکت روی اعضای لیست قبلی می‌نویسیم.

شرط در List Comprehension

می‌دانید که می‌توانیم از شرط های پایتون در بدنه حلقه‌ها استفاده کنیم. یعنی در صورتی که یک شرط خاص برقرار بود، عضو جدیدی به لیست جدید اضافه شود.

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

numbers = [1, 3, 4, 5, 9, 10, 11, 12]
doubled_even_numbers = []

for num in numbers:
    if num % 2 == 0:
        doubled_even_numbers.append(num * 2)

خروجی قطعه کد بالا، لیست زیر است؛ به عبارتی تمام اعداد زوج لیست numbers انتخاب و دو برابر شده‌اند.

[8, 20, 24]

برای ترکیب شرط با Comprehension باید if و سپس condition خود را پس از نوشتن for بنویسیم. توجه داشته باشید که عبارتی condition باید یک مقدار بولین (True/Flase) برگرداند.

numbers = [1, 3, 4, 5, 9, 10, 11, 12]
doubled_even_numbers = [num * 2 for num in numbers if num % 2 == 0]
List Comprehension در پایتون با اعمال شرط خاص
List Comprehension در پایتون با اعمال شرط خاص

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

else در لیست کامپریهنشن

همان‌طور که از if در List Comprehension پایتون می‌توان استفاده کرد، می‌توانیم از ساختار if-else نیز استفاده کنیم.

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

اگر بخواهیم این کار را با حلقه انجام دهیم، کدی شبیه به کد زیر خواهیم داشت:

numbers = [1, 3, 4, 5, 9, 10, 11, 12]
result = []

for num in numbers:
    if num % 2 == 0:
        result.append(num * 2)
    else:
        result.append(num)

معادل کد بالا با روش خلاصه‌سازی لیست‌ها مشابه کد زیر است:

numbers = [1, 3, 4, 5, 9, 10, 11, 12]
result = [num * 2 if num % 2 == 0 else num for num in numbers]
ساختار شرطی if-else در لیست کامپریهنشن
ساختار شرطی if-else در لیست کامپریهنشن

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

با کد زیر، به‌جای اعداد بزرگ‌تر از 10 رشته high و به‌جای اعداد کوچک‌تر از 10 رشته low قرار می‌گیرد:

numbers = [8, 11, 17, 3, 15]
result = ["High" if num >= 10 else "Low" for num in numbers]

# ['Low', 'High', 'High', 'Low', 'High']

معمولاً پیشنهاد می‌شود تا جایی که ممکن است از if-else در لیست کامپریهنشن استفاده نشود؛ مگر در مواردی که شرط ساده و کوتاهی داریم. دلیل پیشنهاد برای عدم استفاده این است که خوانایی کد کمتر و درک آن سخت‌تر می‌شود. اما اگر کدی که می‌نویسید طولانی و درکش سخت نیست، استفاده از List Comprehension پایتون هیچ ایرادی ندارد.

ساختار Comprehension در پایتون

ساختار کلی List Comprehension پایتون را می‌توانیم به شکل زیر در نظر بگیریم:

new_list = [expression for item in iterable if condition]

که در آن:

  • expression مقداری است که به‌عنوان عضو جدید در لیست جدید قرار می‌گیرد. می‌توانید یک مقدار ثابت، فقط متغیر یا عبارتی باشد که مقدار متغیر را تغییر می‌دهد.
  • item نام متغیر انتخابی است که به ازای تمام اعضای لیست قبلی مقداردهی می‌شود.
  • iterable یک مقدار قابل پیمایش است؛ مثل لیست، تاپل پایتون، دیکشنری و هر شیء تکرارگر دیگر.
  • condition شرطی است که می‌خواهیم هنگام پیمایش اعمال شود. این بخش می‌تواند متناسب با نیازمان حذف شود. (شرط نداشته باشیم)
تکرارگرها در پایتون

تکرارگرها در پایتون

کجا از Comprehension استفاده نکنیم؟

به‌طور کلی در سه مورد زیر می‌توانیم از List Comprehension در پایتون استفاده کنیم:

  • ساده‌سازی کدهای کوتاه و تکراری که با حلقه نوشته شده‌اند.
  • فیلتر کردن داده‌ها بر اساس شرط خاص
  • اعمال تغییرات ساده روی اعضای لیست پایتون (با شرط یا بدون شرط خاص)

استفاده بیش از حد از لیست کامپریهنشن می‌تواند خوانایی کد را کاهش دهد. زمانی که Comprehension پیچیده یا دارای چندین شرط و ساختار تودرتو است، بهتر است از این قابلیت استفاده نکنیم.

برای مثال، استفاده از این ساختار برای ایجاد لیستی شبیه به زیر کار مناسبی نیست؛ هر چند که نتیجهٔ دلخواه را به ما می‌دهد. در این‌طور مواقع استفاده از حلقه‌های for می‌تواند بسیار خواناتر باشد.

# شبیه به این را استفاده نکنید! (پیچیده و دشوار برای خواندن)

data = [(x, y) for x in range(5) for y in range(5) if x != y and x + y > 5]

List Comprehension تو در تو

در برخی مواقع می‌توان از این ساختار به‌صورت تودرتو استفاده کرد. هر چند که باید به خوانایی کد هم دقت کنیم. این‌جا فقط برای اینکه بدانید ساختار تودرتو هم قابل تعریف است، مثالی می‌زنم.

در nested list comprehension زیر، یک ماتریس 3 در 3 ایجاد کرده‌ام. در این کد از تابع range() برای ایجاد لیست مرجع استفاده کرده‌ام:

matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]

# output:
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

جمع‌بندی خلاصه لیست

List Comprehension در پایتون راهی سریع و ساده برای ساخت لیست‌های جدید است. این روش باعث افزایش خوانایی کد و کاهش تعداد خطوط کدنویسی می‌شود، اما برای کدهای پیچیده بهتر است از همان روش‌های مرسوم (حلقه‌ها) استفاده کنیم. این روش فقط مخصوص زبان پایتون نیست و می‌توانید نمونه‌های استفاده از آن را در دیگر زبان‌ها در ویکی‌پدیا ببینید.

امیدوارم این آموزش برایتان کاربردی بوده باشد. اگر سؤال یا چالشی در کار با لیست کامپریهنشن دارید، از بخش دیدگاه‌ها بپرسید.