یک list مجموعهای تغییرپذیر از عنصرها بهصورت متوالی است.
مانند بیشتر مجموعهها (به انواع درونی tuple، dict و set نگاه کنید)، لیستها میتوانند به هر نوع داده (یا چند نوع داده) ارجاع داشته باشند، از جمله به لیستهای دیگر.
مانند هر دنباله، میتوان با شمارهی اندیس 0-based index از سمت چپ و -1-based index از سمت راست به عنصرها دسترسی داشت.
لیستها را میتوان بهطور کامل یا جزئی با نماد برش یا <list>.copy() کپی کرد.
لیستها از عملیاتهای دنبالهای هم عمومی و هم تغییرپذیر پشتیبانی میکنند، مانند min()/max()، <list>.index()، <list>.append() و <list>.reverse().
میتوان با ساختار for item in <list> روی عنصرهای لیست پیمایش کرد.
وقتی هم اندیس و هم مقدار عنصر لازم باشد، میتوان از for index, item in enumerate(<list>) استفاده کرد.
در پشت صحنه، lists بهصورت آرایههای پویا پیادهسازی میشوند، مشابه نوع ArrayList در Java، و بیشتر برای نگهداری گروههایی از دادههای مشابه (رشتهها، اعداد، مجموعهها و غیره) با طول نامعلوم به کار میروند.
لیستها ساختار دادهای بسیار انعطافپذیر و پرکاربردی هستند و بسیاری از متدها و عملیات درونی در Python، لیست را بهعنوان خروجی تولید میکنند.
یک list را میتوان بهصورت تحتاللفظی با کروشههای مربعی [] و ویرگول بین عنصرها تعریف کرد:
>>> no_elements = []
>>> no_elements
[]
>>> one_element = ["Guava"]
>>> one_element
['Guava']
>>> elements_separated_with_commas = ["Parrot", "Bird", 334782]
>>> elements_separated_with_commas
['Parrot', 'Bird', 334782]
برای خوانایی، وقتی عنصرهای زیادی وجود داشته باشد یا ساختارهای دادهای تودرتو درون یک list قرار داشته باشند، میتوان از شکست خط استفاده کرد:
>>> lots_of_entries = [
"Rose",
"Sunflower",
"Poppy",
"Pansy",
"Tulip",
"Fuchsia",
"Cyclamen",
"Lavender"
]
>>> lots_of_entries
['Rose', 'Sunflower', 'Poppy', 'Pansy', 'Tulip', 'Fuchsia', 'Cyclamen', 'Lavender']
# Each data structure is on its own line to help clarify what they are.
>>> nested_data_structures = [
{"fish": "gold", "monkey": "brown", "parrot": "grey"},
("fish", "mammal", "bird"),
['water', 'jungle', 'sky']
]
>>> nested_data_structures
[{'fish': 'gold', 'monkey': 'brown', 'parrot': 'grey'}, ('fish', 'mammal', 'bird'), ['water', 'jungle', 'sky']]
سازندهی list() را میتوان خالی یا با یک شیء قابل پیمایش بهعنوان آرگومان به کار برد.
سازنده عنصرهای شیء قابل پیمایش را یکییکی میپیماید و به ترتیب به list اضافه میکند:
>>> no_elements = list()
>>> no_elements
[]
# The tuple is unpacked and each element is added.
>>> multiple_elements_from_tuple = list(("Parrot", "Bird", 334782))
>>> multiple_elements_from_tuple
['Parrot', 'Bird', 334782]
# The set is unpacked and each element is added.
>>> multiple_elements_from_set = list({2, 3, 5, 7, 11})
>>> multiple_elements_from_set
[2, 3, 5, 7, 11]
نتیجهی استفاده از سازندهی list با یک string یا یک dict ممکن است غافلگیرکننده باشد:
# String elements (Unicode code points) are iterated through and added *individually*.
>>> multiple_elements_string = list("Timbuktu")
>>> multiple_elements_string
['T', 'i', 'm', 'b', 'u', 'k', 't', 'u']
# Unicode separators and positioning code points are also added *individually*.
>>> multiple_code_points_string = list('अभ्यास')
>>> multiple_code_points_string
['अ', 'भ', '्', 'य', 'ा', 'स']
# The iteration default for dictionaries is over the keys, so only key data is inserted into the list.
>>> source_data = {"fish": "gold", "monkey": "brown"}
>>> multiple_elements_dict_1 = list(source_data)
['fish', 'monkey']
چون سازندهی list فقط اشیاء قابل پیمایش (یا هیچ آرگومانی) را بهعنوان آرگومان میپذیرد، اشیائی که قابل پیمایش نیستند خطای نوع میاندازند.
در نتیجه، ساختن یک list تکعنصری با روش تحتاللفظی بسیار آسانتر است.
# Numbers are not iterable, and so attempting to create a list with a number passed to the constructor fails.
>>> one_element = list(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
# Tuples *are* iterable, so passing a one-element tuple to the constructor does work, but it's awkward
>>> one_element_from_iterable = list((16,))
>>> one_element_from_iterable
[16]
به عنصرهای درون لیستها (و همچنین عنصرها در دیگر انواع دنبالهای str و tuple) میتوان با 0-based index و نمادگذاری کروشهای دسترسی داشت.
اندیسها میتوانند از left --> right (با شروع از صفر) یا از right --> left (با شروع از -۱) باشند.
| اندیس از چپ ⟹ |
|
⟸ اندیس از راست |
>>> breakfast_foods = ["Oatmeal", "Fruit Salad", "Eggs", "Toast"]
# Oatmeal is at index 0 or index -4.
>>> breakfast_foods[0]
'Oatmeal'
>>> breakfast_foods[-4]
'Oatmeal'
# Eggs are at index -2 or 2
>>> breakfast_foods[-2]
'Eggs'
>>> breakfast_foods[2]
'Eggs'
# Toast is at -1
>>> breakfast_foods[-1]
'Toast'
میتوان به بخشی از عنصرهای درون یک list با نماد برش (<list>[start:stop]) دسترسی داشت.
یک برش دنبالهای از عنصرها در موقعیت index است، بهگونهای که start <= index < stop.
برشزدن نسخهای از عنصرهای «برشخورده» را برمیگرداند و list اصلی را تغییر نمیدهد.
میتوان از پارامتر step هم بهصورت [start:stop:step] استفاده کرد تا از عنصرهای list «رد شد» یا آنها را فیلتر کرد (برای مثال، step برابر ۲ عنصرها را یکی در میان در بازه انتخاب میکند):
>>> colors = ["Red", "Purple", "Green", "Yellow", "Orange", "Pink", "Blue", "Grey"]
# If there is no step parameter, the step is assumed to be 1.
>>> middle_colors = colors[2:6]
>>> middle_colors
['Green', 'Yellow', 'Orange', 'Pink']
# If the start or stop parameters are omitted, the slice will
# start at index zero, and will stop at the end of the list.
>>> primary_colors = colors[::3]
>>> primary_colors
['Red', 'Yellow', 'Blue']
استفاده از تابع درونی sum() روی یک لیست، مجموع همهی اعداد درون لیست را برمیگرداند:
>>> number_list = [1, 2, 3, 4]
>>> sum(number_list)
10
میتوانید طول یک لیست را هم با تابع len() به دست آورید:
>>> long_list = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
>>> len(long_list)
10
لیستها را میتوان به روشهای متفاوتی نیز ترکیب کرد:
# Using the plus + operator unpacks each list and creates a new list, but it is not efficient.
>>> new_via_concatenate = ["George", 5] + ["cat", "Tabby"]
>>> new_via_concatenate
['George', 5, 'cat', 'Tabby']
# Likewise, using the multiplication operator * is the equivalent of using + n times.
>>> first_group = ["cat", "dog", "elephant"]
>>> multiplied_group = first_group * 3
>>> multiplied_group
['cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant']
لیستها یک پیمایشگر فراهم میکنند و میتوان مانند دیگر انواع دنبالهای روی آنها حلقه زد.
# Looping through the list and printing out each element.
>>> colors = ["Orange", "Green", "Grey", "Blue"]
>>> for item in colors:
... print(item)
...
Orange
Green
Grey
Blue
برای توضیحی مفصلتر دربارهی loops و iterators، مفهوم loops را کامل کنید.
Elyse واقعاً بیصبرانه منتظر است که در سفر پیشرویش به Vegas کمی پوکر (و بازیهای کارتی دیگر) بازی کند. او که طرفدار پر و پا قرص «خودردیابی» است، میخواهد چند تابع کوچک بسازد که در کارهای پیگیری به او کمک کند و از شما خواسته است که در فکر کردن به آنها یاریاش کنید.
Elyse بهویژه پوکر را دوست دارد و میخواهد پیگیری کند که چند دور بازی میکند و آنها کدام دورها هستند. هر دور شمارهی خودش را دارد و هر میز، شمارهی دوری را که در حال بازی است نشان میدهد. Elyse یک میز انتخاب میکند و مینشیند تا اولین دورش را بازی کند. قصد دارد سه دور بازی کند.
تابعی به اسم get_rounds(<round_number>) پیادهسازی کنید که شمارهی دور فعلی را میگیرد و یک list برمیگرداند که شامل آن دور و دو دور بعدی است که پیش میآیند:
>>> get_rounds(27)
[27, 28, 29]
Elyse چند دور در میز اول بازی کرد، بعد استراحت کرد و چند دور دیگر در میز دوم بازی کرد... اما در پایان برای هر میز یک لیست متفاوت داشت! او میخواهد آن دو لیست را کنار هم بگذارد تا بتواند همهی دورهای پوکر را در یک جا پیگیری کند.
تابعی به اسم concatenate_rounds(<rounds_1>, <rounds_2>) پیادهسازی کنید که دو لیست میگیرد و یک list برمیگرداند که از همهی دورهای موجود در list اول و سپس همهی دورهای موجود در list دوم تشکیل شده است:
>>> concatenate_rounds([27, 28, 29], [35, 36])
[27, 28, 29, 35, 36]
وقتی صحبت از برخی از دورهای قبلی پوکر میشود، بازیکن دیگری اشاره میکند که دو تای آنها چقدر شبیه هم پیش رفتند. Elyse مطمئن نیست که آن دورها را بازی کرده است یا نه.
تابعی به اسم list_contains_round(<rounds>, <round_number>) پیادهسازی کنید که دو ورودی میگیرد: یک لیست از دورهای بازیشده و یک شمارهی دور.
این تابع اگر آن دور در لیست دورهای بازیشده باشد True و در غیر این صورت False برمیگرداند:
>>> list_contains_round([27, 28, 29, 35, 36], 29)
True
>>> list_contains_round([27, 28, 29, 35, 36], 30)
False
Elyse میخواهد بازی جدیدی به اسم Black Joe را امتحان کند. این بازی شبیه Black Jack است، یعنی هدف این است که مجموع کارتهای دستتان به یک مقدار مشخص برسد، اما در Black Joe هدف این است که میانگین مقادیر کارتها ۷ شود. میانگین را میتوان با جمع کردن همهی مقادیر کارتها و سپس تقسیم آن مجموع بر تعداد کارتهای دست به دست آورد.
تابعی به اسم card_average(<hand>) پیادهسازی کنید که میانگین مقادیر یک دست Black Joe را برمیگرداند.
>>> card_average([5, 6, 7])
6.0
در Black Joe، سرعت مهم است. Elyse میخواهد روشی سریعتر برای پیدا کردن میانگین پیدا کند.
او به دو روش برای رسیدن به عددی شبیه میانگین فکر کرده است:
تابع approx_average_is_average(<hand>) را پیادهسازی کنید؛ در اینجا hand لیستی است که مقادیر کارتهای دستتان را در خود دارد.
اگر یکی or هر دو از روشهای نامبردهشده در بالا به عددی برابر با میانگین واقعی برسند، True برگردانید.
نکته: طول همهی دستها فرد است تا پیدا کردن میانه سادهتر شود.
>>> approx_average_is_average([1, 2, 3])
True
>>> approx_average_is_average([2, 3, 4, 8, 8])
True
>>> approx_average_is_average([1, 2, 3, 5, 9])
False
Elyse که از نتایج آزمایش میانگینگیریاش کنجکاو شده، میخواهد بداند آیا گرفتن میانگین کارتهای مکانهای زوج در مقابل میانگین کارتهای مکانهای فرد نتیجهی یکسانی میدهد یا نه. وقت یک تابع آزمایشی دیگر است!
تابعی به اسم average_even_is_average_odd(<hand>) پیادهسازی کنید که یک «مقدار منطقی» برمیگرداند و نشان میدهد آیا میانگین کارتهای ایندکسهای زوج با میانگین کارتهای ایندکسهای فرد یکسان است یا نه.
>>> average_even_is_average_odd([1, 2, 3])
True
>>> average_even_is_average_odd([1, 2, 3, 4])
False
هر یازدهمین دست در Black Joe یک دست امتیازی با یک قاعدهی امتیازی است: اگر آخرین کارتی که میکشید یک جک باشد، ارزش آن را دو برابر میکنید.
تابعی به اسم maybe_double_last(<hand>) پیادهسازی کنید که یک دست میگیرد و بررسی میکند آیا آخرین کارت یک جک (۱۱) است.
اگر آخرین کارت واقعاً جک (۱۱) باشد، پیش از برگرداندن دست، ارزش آن را دو برابر کنید.
>>> hand = [5, 9, 11]
>>> maybe_double_last(hand)
[5, 9, 22]
>>> hand = [5, 9, 10]
>>> maybe_double_last(hand)
[5, 9, 10]