ساختمان‌های داده؛ چهار ابرقهرمان که هرج‌ومرج رو به نظم تبدیل می‌کنن
تا اینجا یاد گرفتیم چطور با متغیرها حرف بزنیم، با عملگرها حساب کتاب کنیم، با شرط‌ها تصمیم بگیریم و با حلقه‌ها تکرار رو به ماشین بسپاریم. اما یه سوال: وقتی کلی داده داریم (مثلاً صدتا اسم دانشجو، یا هزارتا عدد سنسور)، اینا رو کجا بذاریم؟ صدتا متغیر بسازیم؟ مسلماً نه. اینجاست که ساختمان‌های داده وارد می‌شن: مثل کمد، قفسه و کیف‌های جادویی که اطلاعات رو مرتب و منظم نگه می‌دارن و هر وقت لازم داشتی سریع تحویلت می‌دن.

پایتون چهارتا از این قفسه‌های آماده رو در اختیارت می‌ذاره که هر کدوم یه ابرقهرمان توی یه زمینه‌ان:

لیست (List) – کمد همه‌چیزخور با شمارهٔ ردیف

تاپل (Tuple) – جعبهٔ امانات تغییرناپذیر

مجموعه (Set) – گونی بی‌نظم اما بدون عضو تکراری

دیکشنری (Dictionary) – صندوق کلید-مقدار با برچسب

بریم ببینیم هر کدوم چه جوری دنیای کد رو مرتب می‌کنن و کی باید از کدومش استفاده کنیم.

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


# یه لیست ساده
fruits = ["سیب", "موز", "پرتقال", "هندوانه"]
mixed = [1, "سلام", 3.14, True, [5, 6]]  # لیست مختلط هم مجازه
empty = []                                 # لیست خالی


دسترسی و تغییر: با ایندکس (مثل رشته‌ها) به هر خونه دسترسی داری و می‌تونی تغییرش بدی. برش (Slicing) هم اینجا مثل آب خوردن کار می‌کنه.


print(fruits[0])       # سیب
print(fruits[-1])      # هندوانه
print(fruits[1:3])     # ['موز', 'پرتقال']

fruits[1] = "گیلاس"    # موز رو به گیلاس تغییر بده
print(fruits)          # ['سیب', 'گیلاس', 'پرتقال', 'هندوانه']


متدهای خفن: لیست یه عالمه متد داره که خودش رو تغییر می‌ده (چون لیست تغییرپذیر (Mutable) هست، یعنی می‌تونی بدون ساختن لیست جدید، توش دست ببری).

تصویر

نمونه:


nums = [3, 1, 4, 1, 5]
nums.append(9)        # [3, 1, 4, 1, 5, 9]
nums.insert(2, 99)    # [3, 1, 99, 4, 1, 5, 9]
nums.remove(1)        # اولین 1 رو پاک می‌کنه: [3, 99, 4, 1, 5, 9]
last = nums.pop()     # 9 رو برمی‌گردونه و حذف می‌کنه
print(nums)           # [3, 99, 4, 1, 5]
nums.sort()
print(nums)           # [1, 3, 4, 5, 99]


نکتهٔ مهم: وقتی می‌نویسی list2 = list1، هر دو به یک لیست در حافظه اشاره می‌کنن. اگر یکی رو تغییر بدی، دیگری هم عوض می‌شه. برای کپی واقعی از list2 = list1.copy() یا list2 = list1[:] استفاده کن.

لیست تو در تو (ماتریس):


matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[1][2])   # 6


تاپل (Tuple) – لیست ضدضربه
تاپل دقیقاً شبیه لیسته، با یه تفاوت سرنوشت‌ساز: تغییرناپذیر (Immutable). وقتی تاپل رو ساختی، دیگه نمی‌تونی عضوهایش رو عوض کنی، حذف کنی یا اضافه کنی. مثل یه عکس دسته‌جمعی که بعد از ثبت، دیگه نمی‌شه کسی رو ازش پاک کرد. از پرانتز () برای ساختنش استفاده می‌کنی.


colors = ("قرمز", "سبز", "آبی")
single = (42,)   # تاپل تک‌عضوی حتماً یه ویرگول می‌خواد
empty = ()        # تاپل خالی

print(colors[0])      # قرمز
print(colors[1:3])    # ('سبز', 'آبی')
# colors[0] = "زرد"  # خطا! TypeError


چرا تاپل وقتی لیست هست؟

سرعت بالاتر و مصرف حافظه کمتر نسبت به لیست.

ایمنی داده: وقتی بخوای مطمئن بشی یه مجموعه از مقادیر دست‌نخورده باقی می‌مونن (مثل روزهای هفته، مختصات یه نقطه).

قابل استفاده به‌عنوان کلید دیکشنری (برخلاف لیست).

بعضی توابع چند مقدار را در قالب تاپل برمی‌گردونن.

مثال: جابجایی دو متغیر با تاپل (Unpacking):


a, b = 5, 10
a, b = b, a   # عملاً داریم تاپل (b, a) رو unpack می‌کنیم
print(a, b)   # 10 5


مجموعه (Set) – گونی بی‌نظم بدون تکراری
مجموعه مثل یه گونی‌ست که هر چی توش بریزی، ترتیب خاصی نداره و هر چیزی فقط یک بار می‌تونه توش باشه. انگار یه جعبهٔ قرعه‌کشی: قرعه‌ها رو می‌ریزی توش، دوباره‌ای در کار نیست و نمی‌دونی کی بیرون میاد. از آکولاد {} یا تابع set() می‌سازی.


fruits = {"سیب", "موز", "سیب", "پرتقال"}  # سیب دوباره نادیده گرفته می‌شه
print(fruits)   # {'پرتقال', 'موز', 'سیب'} (ترتیب ممکنه فرق کنه)

empty_set = set()  # دقت: {} خالی یعنی دیکشنری، نه مجموعه!

nums = [1, 2, 2, 3, 3, 3]
unique = set(nums)          # {1, 2, 3}


عملیات مجموعه‌ای (ریاضی): می‌تونی اجتماع، اشتراک، تفاضل و ... بگیری. اینا رو با عملگرها یا متدها انجام می‌دی:

تصویر


a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)   # {1, 2, 3, 4, 5, 6}
print(a & b)   # {3, 4}
print(a - b)   # {1, 2}
print(a ^ b)   # {1, 2, 5, 6}


متدهای کاربردی: add(), remove(), discard() (بدون خطا اگر نبود)، clear().

نکته: مجموعه فقط اعضای تغییرناپذیر می‌پذیره (عدد، رشته، تاپل) ولی لیست رو نه. چون باید بتونه تشخیص بده تکراری هست یا نه.

کجا به درد می‌خوره؟ حذف داده‌های تکراری از لیست، تست عضویت سریع (in روی مجموعه از in روی لیست خیلی سریع‌تره)، عملیات ریاضی مثل دایرهٔ دوستان مشترک.

دیکشنری (Dictionary) – صندوق امانات با برچسب
دیکشنری شاه‌کار پایتونه. به جای شماره (ایندکس)، هر مقداری رو با یه کلید (Key) برچسب‌گذاری می‌کنی. مثل دفترچه تلفن که اسم هرکی رو بزنی، شماره‌اش میاد. کلید معمولاً رشته یا عدد (یا هر چیز تغییرناپذیر) و مقدار می‌تونه هر چی باشه. با آکولاد {} و :key: value می‌سازی.


student = {
    "name": "آرش",
    "age": 21,
    "grades": [18, 19, 17.5],
    "is_active": True
}

print(student["name"])      # آرش
print(student["grades"])    # [18, 19, 17.5]
student["age"] = 22         # تغییر مقدار
student["city"] = "تهران"   # افزودن کلید جدید


متدهای ضروری:

تصویر


for key in student.keys():
    print(key, end=" ")   # name age grades is_active city
for value in student.values():
    print(value)
for k, v in student.items():
    print(f"{k}: {v}")


چرا get() معرکه‌ست؟


# به جای:
if "phone" in student:
    print(student["phone"])
else:
    print("ندارد")

# می‌نویسی:
print(student.get("phone", "موجود نیست"))


نکته: از پایتون 3.7 به بعد، دیکشنری ترتیب ورود کلیدها رو حفظ می‌کنه (اما به ترتیب ایندکس عددی نیست).

کی از دیکشنری استفاده کنم؟ هر جا نیاز به نگاشت سریع بین یک چیز و چیز دیگه داری: شمارش فراوانی کلمات، کش کردن نتایج، ساختارهای JSON، پروفایل کاربر، تنظیمات برنامه. عملاً قلب هر برنامهٔ واقعی یه دیکشنری بزرگه.

یک نبرد باحال: کدوم رو کی انتخاب کنم؟

تصویر

نمایش بزرگ: مدیریت یه فروشگاه کوچیک
بیایم همهٔ این قفسه‌ها رو یه جا توی یه برنامهٔ مدیریت فروشگاه نشون بدیم:


# فروشگاه گُل و گیاه
inventory = ["گلدون", "خاک", "کود", "بذر"]   # لیست برای اجناس (ترتیب داره)
prices = {
    "گلدون": 15000,
    "خاک": 5000,
    "کود": 12000,
    "بذر": 8000
}                                           # دیکشنری برای قیمت‌ها
categories = {("گلدون", "خاک")}             # مجموعه‌ای از تاپل‌ها (تغییرناپذیر)
offers = ("تخفیف ۱۰٪", "ارسال رایگان")      # تاپل برای پیشنهادات ثابت

# مشتری خرید می‌کنه
cart = []
while True:
    item = input("چی می‌خوای بخری؟ (تمام = خالی بذار): ")
    if not item:
        break
    if item not in inventory:
        print("جنس موجود نیست!")
        continue
    if item not in prices:
        print("قیمت نداره؟!")
        continue
    cart.append(item)
    print(f"{item} به سبد اضافه شد.")

# حذف خریدهای تکراری با مجموعه
unique_items = set(cart)
print(f"اقلام خرید: {unique_items}")

# محاسبه قیمت با دیکشنری
total = 0
for product in cart:
    total += prices[product]
print(f"مبلغ کل بدون تخفیف: {total:,} تومان")

# اعمال تخفیف‌های ثابت (تاپل)
if total > 50000:
    print("شامل تخفیف ویژه شدی:", offers[0])
    total *= 0.9
print(f"مبلغ نهایی: {total:,.0f} تومان")


همه رو یه جا دیدی: لیست برای سبد خرید و موجودی، دیکشنری برای قیمت‌ها، مجموعه برای یکتاسازی، تاپل برای پیشنهادات غیرقابل تغییر. حالا دیگه می‌تونی هر برنامهٔ واقعی رو با این ابزارها سروسامون بدی.

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

دفعهٔ بعد که داده‌های زیادی دور و برت بودن، یاد این چهارتا ابرقهرمان بیفت. با اینا می‌تونی هر چیزی رو از یک لیست خرید ساده تا یک شبکهٔ اجتماعی رو سازمان بدی. حالا برو و جهان داده‌هات رو مرتب کن! 🗃️🐍✨