Barcha qo'llanmalar

Python'da hashmap'lar: implementatsiya va use case'larni puxta o'zlashtiring

Hashmap'lar Python'da hamma joyda uchraydi va ehtimol siz ulardan avval ham foydalangansiz. Python'da hashmap'lardan qanday foydalanishni keng tarqalgan xatolar va misollar bilan o'rganing.

Muallif: William Imoh

Agar siz Python dasturchisi sifatida ma'lumotlar bazasidan username qidirish, list'dagi elementlarni sanash yoki API javobini keshlashni qo'llab-quvvatlaydigan ilovalar yaratgan bo'lsangiz, ehtimol hashmap'dan bevosita yoki uning implementatsiyalaridan biri orqali foydalangansiz.

Hashmap'lar hamma joyda uchraydi va zamonaviy dasturlash tillarining ko'plab qismlariga quvvat beradi. Ular ma'lumotlarni olishni tezlashtiradi, unumdorlikni oshiradigan keshlash qatlamlarini qo'llab-quvvatlaydi va toza hamda samarali bo'lib qoladigan kod yozishga yordam beradi. Python'da dictionary data type'i ma'lumotlarni saqlash uchun standart hashmap vazifasini bajaradi. Bu sizga quyi darajadagi xotira tafsilotlari yoki qo'lda hashing bilan shug'ullanmasdan kuchli va samarali ma'lumotlar tuzilmasini beradi.

Ushbu qo'llanmada siz Python hashmap'lari ichki tomondan qanday ishlashini, ulardan qanday samarali foydalanishni va ular real loyihalarda qayerda o'zini eng yaxshi ko'rsatishini bilib olasiz.

Python'da hashmap nima?

Hashmap — ma'lumotlarni key-value juftliklari ko'rinishida saqlaydigan ma'lumotlar tuzilmasi. Har bir noyob key aynan bitta value'ga mos keladi, bu esa tez lookup qilish imkonini beradi. Hashmap elementlarni bir xil kirish qiymati bilan birma-bir qidirib chiqish o'rniga hash funksiyadan foydalanib to'g'ridan-to'g'ri siz istagan value'ga sakrab o'tadi.

Hash funksiya — key'ni songa aylantiradigan matematik amal. Bu son value xotiraning qayerida saqlanishini belgilaydi, lookup'larning bunchalik tezligi ham shu bilan izohlanadi. Shunday qilib, Python list'dagi kabi har bir elementni skanerlash o'rniga to'g'ridan-to'g'ri kerakli joyga boradi va bir xil kirish qiymati uchun bir xil natijani kafolatlaydi. Bu jarayon ma'lumotlarni tez olish uchun juda muhim.

Python'da hashmap

Quyida Python'da dictionary yordamida yaratilgan hashmap misoli keltirilgan:

user_data = {
    "user_123": {"name": "Alice", "email": "alice@example.com"},
    "user_456": {"name": "Bob", "email": "bob@example.com"},
    "user_789": {"name": "Charlie", "email": "charlie@example.com"}
}

# Fast lookup - goes directly to the value
print(user_data["user_456"])  # {'name': 'Bob', 'email': 'bob@example.com'}

Ichki tomondan, key-value juftligini saqlaydigan hashmap yaratganingizda Python quyidagilarni bajaradi:

  1. U built-in hash() funksiyasi yordamida har bir key'ning hash'ini hisoblaydi.

  2. U value'ni qaysi bucket'ga joylashtirishni aniqlash uchun shu hash'dan foydalanadi.

  3. Value'ni saqlashdan oldin u bucket allaqachon band yoki band emasligini tekshiradi. Agar band bo'lsa — bu collision deb ataladi — Python belgilangan pattern bo'yicha keyingi bo'sh bucket'ni probing qiladi.

Hashmap qanday ishlaydi

Bucket'lar, hash funksiya, collision'lar va ularning ahamiyati

Bucket — bu shunchaki ichki saqlash massividagi pozitsiya. Uni pochta qutisiga o'xshatish mumkin: har bir key o'z hash'iga qarab pochta qutisi raqamini oladi. Har safar key qo'shganingizda Python hash(key)'ni hisoblaydi va key qayerga borishi kerakligini hal qilish uchun shu qiymatdan foydalanadi.

Har bir key noyob bucket'ga tushganda bu yaxshi ishlaydi. Ikki xil key bir xil bucket'ga to'g'ri kelganda vaziyat qiziqroq tus oladi. Bu holat collision deb ataladi.

Hashmap'da collision yo'qligi va collision

Collision ma'lumotlaringiz yo'qolganini anglatmaydi. Python keyingi bo'sh bucket'ni topish uchun probing bilan open addressing deb ataladigan strategiyadan foydalanadi. U bo'sh joy topmaguncha probing qilishda davom etadi. Bu yondashuv barcha yozuvlarni bitta ixcham massivda saqlaydi. Bundan farqli o'laroq, boshqa ko'plab tillar separate chaining'dan foydalanadi: unda har bir bucket bir xil bucket'ni bo'lishadigan key-value juftliklaridan iborat tashqi linked list'ga ishora qiladi.

Dictionary o'sgan sari, agar Python o'zining ichki massivi hajmini boshqarmaganida, collision'lar tez-tez sodir bo'lishi mumkin edi. Dictionary ma'lum bir load factor'ga yetganda Python kattaroq hash table ajratib, yozuvlarni rehash qilish orqali hash table hajmini o'zgartiradi. Bu kamdan-kam sodir bo'ladi va vaqt o'tishi bilan amallarning tez bo'lib qolishiga yordam beradi.

Collision'lar xavfsizlik uchun ham muhim. Agar ko'plab key'lar o'xshash hash pattern'larini hosil qilsa, hujumchi ataylab collision'larni keltirib chiqarib, dasturingizni sekinlashtirishi mumkin. Python buni string'lar uchun tasodifiylashtirilgan hash funksiyalardan foydalanish orqali yumshatadi, bu esa bunday hujumlarni ancha qiyinlashtiradi.

Python'da hashmap'larni amalga oshirish

Python dictionary'lari hashmap'lar bilan ishlashning eng qulay usuli, shuning uchun hash funksiyalarni amalga oshirish yoki bucket'larni o'zingiz boshqarish haqida qayg'urishingiz shart emas. Til bu murakkablikning barchasini o'z zimmasiga oladi va sizga toza hamda intuitiv interfeys taqdim etadi. Keling, value'larni tez yaratish, o'zgartirish va olish uchun kundalik kod yozishda ishlatadigan asosiy amallarni ko'rib chiqaylik.

Dictionary yordamida hashmap yaratish

Python'da dictionary yaratishning bir nechta usuli bor. Eng keng tarqalgan yondashuv jingalak qavslar {} dan foydalanadi:

inventory = {
    "apples": 50,
    "bananas": 30,
    "oranges": 25
}

# Empty dictionary
storage = {}

Yana bir qulay variant — Python'ning built-in dict() constructor'idan foydalanish. U keyword argument'lar yoki iterable key-value juftliklarini qabul qilib, har bir key'ni dictionary'da saqlashdan oldin ichki tomondan hash qilish orqali hashmap yaratadi:

# Using the dict() constructor
config = dict(host="localhost", port=8080, debug=True)

Shuni ta'kidlash muhimki, dictionary key'lari noyob bo'lishi kerak. Agar takroriy key'larni belgilasangiz, Python xato ko'tarmaydi. Buning o'rniga u muayyan key'ning oxirgi uchrashuvini saqlab qoladi va oldingisini tashlab yuboradi:

inventory = {
    "apples": 50,
    "bananas": 30,
    "oranges": 25,
    "oranges": 37,
}

print(inventory) # {'apples': 50, 'bananas': 30, 'oranges': 37}

Hashmap'da qidirish

Hashmap yaratishdan tashqari, sizga ko'pincha uning ichida saqlangan value'larni qidirish kerak bo'ladi. Value'ni olish uchun kvadrat qavslar ichida key'ni ko'rsating va Python tegishli value'ni qaytaradi:

inventory = {
    "apples": 50,
    "bananas": 30,
    "oranges": 25
}

# key exists
print(inventory["oranges"]) # 25 

Agar mavjud bo'lmagan key'ga murojaat qilishga urinsangiz, Python KeyError ko'taradi. Masalan, inventory["pineapple"]'ga murojaat qilish quyidagi xatoga olib keladi:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    print(inventory["pineapple"])
KeyError: 'pineapple'

Hashmap'larda qidirish bo'yicha qaror sxemasi

Production kodida get() method'i ko'pincha yaxshiroq tanlov hisoblanadi, chunki u key yo'q bo'lganda dastur ishdan chiqishining oldini oladi. Agar key mavjud bo'lmasa, get() xato ko'tarish o'rniga standart holatda None qaytaradi:

inventory.get("pineapple") # None

Agar o'zingizning standart qiymatingizni xohlasangiz, fallback qiymat ham berishingiz mumkin.

Hashmap'ga qo'shish

Yangi key'ga value berish orqali hashmap'ga yangi yozuvlar qo'shishingiz mumkin:

inventory["lemons"] = 55

print(inventory) # {'apples': 50, 'bananas': 30, 'oranges': 25, 'lemons': 55}

Hashmap'ni yangilash

Mavjud key'ni yangilash yangisini qo'shish bilan bir xil sintaksisdan foydalanadi. Agar key allaqachon mavjud bo'lsa, yangi value berish mavjud yozuvni yangi value bilan yangilaydi; agar key mavjud bo'lmasa, u yaratiladi.

inventory["apples"] = 30

print(inventory) # {'apples': 30, 'bananas': 30, 'oranges': 25, 'lemons': 55}

Hashmap'dan value'larni o'chirish

Hashmap'dan key-value juftligini olib tashlash uchun del kalit so'zini muayyan key bilan birga ishlating. U index bo'yicha list'dan elementlarni o'chirishdagi kabi ishlaydi:

del inventory["apples"]

print(inventory) # {'bananas': 30, 'oranges': 25}

Python, shuningdek, dictionary'dan barcha key-value juftliklarini olib tashlaydigan clear() method'ini ham taqdim etadi:

inventory.clear()

print(inventory) # {}

Foydali dictionary method'lari

Asosiy yaratish, o'qish, yangilash va o'chirish amallaridan tashqari, Python dictionary'larida hashmap'lar bilan ishlashni osonlashtiradigan bir nechta yordamchi method'lar mavjud.

items() method'i barcha key-value juftliklarining view'ini qaytaradi:

items = inventory.items()

print(items) # dict_items([('apples', 50), ('bananas', 30), ('oranges', 25)])

keys() method'i barcha key'larni o'z ichiga olgan view qaytaradi:

keys = inventory.keys()

print(keys) # dict_keys(['apples', 'bananas', 'oranges'])

values() method'i hashmap'dagi value'larga murojaat qilishga yordam beradi:

values = inventory.values()

print(values) # dict_values([50, 30, 25])

Python dictionary'lari hashmap'larning kuchli va samarali built-in implementatsiyasini taqdim etsa-da, ular Python'da key-value mapping'larni modellashtirishning yagona usuli emas. Ba'zi vaziyatlarda tartib qoidalari, standart qiymatlar yoki unumdorlik bo'yicha muayyan tradeoff'lar kabi omillar muqobil yondashuvlarni talab qilishi mumkin. Keyingi bo'limda Python'da hashmap'ga o'xshash tuzilmalarni yaratish va ular bilan ishlashning boshqa usullari ko'rib chiqiladi.

Python'da hashmap yaratishning muqobil usullari

Dictionary yaratish uchun {}'dan foydalanish Python'da ko'pincha odatiy holdek tuyuladi — toki u sizning ehtiyojingizga mos kelmay qolgunga qadar. Siz ikkita list'ni key-value juftliklariga aylantirayotgan, standart qiymatlarni initialize qilayotgan yoki murakkabroq ma'lumotlardan hashmap'ni shu zahotiyoq qurayotgan bo'lishingiz mumkin. Python bu stsenariylarning barchasi uchun built-in funksiyalar va vositalarni taqdim etadi. Quyida use case'ingizga qarab foydalanishingiz mumkin bo'lgan bir nechta muqobil hashmap implementatsiyalari keltirilgan.

collections.defaultdict

defaultdict mavjud bo'lmagan key'lar uchun avtomatik ravishda standart qiymat yaratadi. Bu key mavjudligini qo'lda tekshirish zaruratini yo'qotadi va KeyError exception'laridan qochishga yordam beradi.

from collections import defaultdict

# Grouping items by category
products_by_category = defaultdict(list)
products = [
    ("Electronics", "Laptop"),
    ("Electronics", "Phone"),
    ("Clothing", "Shirt"),
    ("Electronics", "Tablet"),
    ("Clothing", "Pants")
]

# Loop through each (category, product) pair and 
# if the key does not exist create an empty list for it
for category, product in products:
    products_by_category[category].append(product)

print(dict(products_by_category))
# {'Electronics': ['Laptop', 'Phone', 'Tablet'], 'Clothing': ['Shirt', 'Pants']}

collections.Counter

Counter — hashable obyektlarni sanash uchun mo'ljallangan maxsus hashmap. U odatda analitika, chastotani kuzatish va tezkor xulosalar uchun ishlatiladi.

from collections import Counter

# Analyzing page views
page_views = ["home", "about", "home", "contact", "home", "about", "home"]
view_counts = Counter(page_views)

print(view_counts)  # Counter({'home': 4, 'about': 2, 'contact': 1})
print(view_counts.most_common(2))  # [('home', 4), ('about', 2)]

collections.OrderedDict

OrderedDict qo'shilish tartibini aniq saqlaydi. Oddiy dictionary'lar Python 3.7 dan boshlab qo'shilish tartibini saqlasa-da, OrderedDict'ni hali ham legacy code'da yoki uning move_to_end() kabi maxsus method'lari foydali bo'lgan holatlarda ko'rishingiz mumkin.

from collections import OrderedDict

od = OrderedDict()
od["a"] = 1
od["b"] = 2

collections.ChainMap

ChainMap bir nechta dictionary'ni bitta mantiqiy hashmap'ga guruhlaydi. Bu value'lar yuqoriroq ustuvorlikka ega scope'lar tomonidan qayta yozilishi mumkin bo'lgan qatlamli konfiguratsiyalar uchun yaxshi ishlaydi.

from collections import ChainMap

defaults = {"debug": False}
env = {"debug": True}

config = ChainMap(env, defaults)

types.MappingProxyType

MappingProxyType dictionary'ning read-only view'ini taqdim etadi. U konfiguratsiya yoki umumiy ma'lumotlarni ochib berib, ayni paytda ularning tasodifan o'zgartirilishining oldini olmoqchi bo'lganingizda foydali.

from types import MappingProxyType

d = {"a": 1}
readonly = MappingProxyType(d)

shelve

shelve disk xotirasiga asoslangan persistent yangi key-value juftligini yaratishning oddiy usulini taklif qiladi. U to'liq ma'lumotlar bazasi tizimini joriy qilmasdan yengil persistence kerak bo'lganda foydali.

import shelve

with shelve.open("data.db") as db:
    db["x"] = 10

Endi siz Python'da hashmap'ga o'xshash tuzilmalarni yaratishning bir nechta usulini ko'rdingiz, navbatdagi savol — ulardan qachon foydalanish kerak. Hashmap'lar real Python dasturlarida hamma joyda uchraydi va ko'pincha muammolarni boshqa ma'lumotlar tuzilmalariga qaraganda tozaroq hal qiladi. Keyingi bo'limda hashmap'larning amaliy qo'llanilishi va ular kundalik Python dasturlashiga qanday mos tushishi ko'rib chiqiladi.

Hashmap'larning amaliy qo'llanilishi

Hashmap'lar — har doim ham sezmasangiz-da, doimo foydalanadigan ma'lumotlar tuzilmalaridan biri. Masalan, dictionary'lar key'ni uni qayta ishlaydigan funksiyaga mapping qilib, switch uslubidagi dispatch uchun ishlatiladi. Ularning ma'lumotlarni tez saqlash va olish qobiliyati ularni ko'plab real stsenariylarda foydali qiladi. Quyida bir nechta keng tarqalgan va amaliy use case'lar keltirilgan.

Keshlash va memoization

Hashmap'lar hisoblash yoki olish qimmatga tushadigan ma'lumotlarni saqlash uchun keng qo'llaniladi. G'oya oddiy. Value bir marta hisoblangach, u noyob key yordamida hashmap'da saqlanadi. Keyingi safar shu value kerak bo'lganda uni qayta hisoblash o'rniga darhol olish mumkin.

Chastotalarni sanash va analitika

Biror narsa qanchalik tez-tez uchrashini sanash data science, analitika va ma'lumotlarni qayta ishlashda juda keng tarqalgan vazifa. Hashmap'lar har bir elementni uning soniga mapping qilish orqali buni oddiy qiladi. Masalan, hujjatdagi so'zlar necha marta uchrashini sanashingiz, biror hodisa qanchalik tez-tez sodir bo'lishini kuzatishingiz yoki ilovadagi foydalanuvchi harakatlarini umumlashtirishingiz mumkin.

Ma'lumotlar bazasida indexing va lookup'lar

Yuqori darajada qaraganda, ko'plab ma'lumotlar bazasi index'lari hashmap'lar kabi ishlaydi. Ular ma'lumotlar bazasiga har bir satrni skanerlamasdan ID, email yoki username kabi key asosida yozuvlarni tez topish imkonini beradi.

Ilova kodida hashmap'lar yengil in-memory index'lar vazifasini ham bajarishi mumkin. Yozuv ID'larini obyektlarga mapping qilish orqali ma'lumotlarga darhol murojaat qilishingiz mumkin. Bu pattern ORM'larda, in-memory ma'lumotlar bazalarida va keshlash qatlamlarida keng tarqalgan.

Guruhlash va aggregation

Hashmap'lar o'zaro bog'liq ma'lumotlarni guruhlash uchun tabiiy ravishda mos keladi. Kategoriyani ifodalash uchun key'dan foydalanib, unga tegishli barcha value'larni shu key ostida saqlashingiz mumkin. Misollar qatoriga buyurtmalarni mijoz ID'si bo'yicha, log yozuvlarini sana bo'yicha yoki mahsulotlarni kategoriya bo'yicha guruhlash kiradi. Ma'lumotlar bo'ylab iteratsiya qilganingizda hashmap murakkab ma'lumotlar tuzilmalarisiz natijalarni samarali tartibga solish va aggregate qilishga yordam beradi.

Konfiguratsiyani boshqarish

Konfiguratsiya sozlamalari ko'pincha key-value juftliklari sifatida saqlanadi, bu esa hashmap'larni ideal tanlovga aylantiradi. Ular sozlamalarni fayllardan, environment variable'lardan yoki masofaviy servislardan yuklash va ularga butun ilovangiz bo'ylab tez murojaat qilish imkonini beradi.

Keng tarqalgan xatolar va best practice'lar

Hashmap'lar kuchli va foydalanish oson, lekin ular bilan bog'liq bir nechta keng tarqalgan tuzoqlar ham bor. Bu xatolarni tushunish va best practice'larga amal qilish bug'lardan qochish, unumdorlikni oshirish va tozaroq kod yozishga yordam beradi.

Mutable obyektlarni key sifatida ishlatish

Keng tarqalgan xatolardan biri — list'lar yoki dictionary'lar kabi mutable obyektlarni hashmap key'lari sifatida ishlatish. Hashmap key'lari immutable va hashable bo'lishi kerak, chunki agar key qo'shilgandan keyin o'zgarsa, hashmap uni boshqa topa olmasligi mumkin.

Best practice: Ishonchli lookup'lar uchun key sifatida string'lar, sonlar yoki tuple'lar kabi immutable type'lardan foydalaning. Agar sizga murakkab key kerak bo'lsa, u immutable ekanligi va barqaror hash qiymatiga ega ekanligiga ishonch hosil qiling.

Hashmap'lardan haddan tashqari ko'p foydalanish

Hashmap'lar tez, lekin ular har doim ham to'g'ri vosita emas. List, set yoki oddiy o'zgaruvchi yetarli bo'ladigan joyda ulardan foydalanish keraksiz murakkablik va ortiqcha xotira sarfini keltirib chiqarishi mumkin.

Best practice: Muammoga mos keladigan eng oddiy ma'lumotlar tuzilmasini tanlang. Hashmap'lardan haqiqatan ham key bo'yicha tez lookup'lar yoki mapping'lar kerak bo'lganda foydalaning.

Unumdorlik va xotira xarajatlarini e'tiborsiz qoldirish

Hashmap'lar o'rtacha konstant vaqtli amallarni taklif qilsa-da, ular ba'zi muqobillarga qaraganda ko'proq xotira sarflaydi. Juda katta hashmap'lar yoki chuqur ichma-ich joylashgan dictionary'lar ham unumdorlikka ta'sir qilishi mumkin.

Best practice: Hajm va foydalanish pattern'lariga e'tibor bering. Ishlatilmayotgan yozuvlarni tozalang, haddan tashqari ichma-ich joylashtirishdan qoching va use case'ingiz uchun boshqa tuzilma yoki yondashuv samaraliroq bo'lmasligini o'ylab ko'ring.

Hashmap'lar tartiblangan deb hisoblash

Hashmap'lar har doim tartibni saqlaydi deb hisoblamang. Zamonaviy Python dictionary'lari qo'shilish tartibini saqlasa-da, agar tartib dizaynning aniq qismi bo'lmasa, algoritmning to'g'riligi uchun bu xatti-harakatga tayanmaslik kerak.

Best practice: Agar tartib sizning mantiqingiz uchun muhim bo'lsa, buni aniq ko'rsating. Yashirin xatti-harakatga tayanish o'rniga kerak bo'lganda tartiblangan ma'lumotlar tuzilmalaridan foydalaning yoki key'larni sort qiling.

Mavjud bo'lmagan key'larni to'g'ri qayta ishlamaslik

Mavjud bo'lmagan key'ga murojaat qilish xatolarga yoki kutilmagan xatti-harakatga olib kelishi mumkin. Bu ko'pincha foydalanuvchi kiritgan ma'lumotlar, tashqi ma'lumotlar yoki to'liq bo'lmagan dataset'lar bilan ishlaganda sodir bo'ladi.

Best practice: Key'larga murojaat qilishdan oldin get(), defaultdict yoki aniq tekshiruvlar kabi xavfsiz murojaat pattern'laridan foydalaning. Bu yondashuvlar kodingizni ishonchliroq qiladi.

Xulosa

Hashmap'lar — bir marta tushunib olganingizdan keyin doimo foydalanadigan fundamental tushunchalardan biri. Python'ning dictionary implementatsiyasi ularni unumdorlikdan voz kechmagan holda qulay qiladi, shuning uchun ular oddiy skriptlardan tortib katta miqyosdagi distributed system'largacha hamma narsada uchraydi.

Agar hashmap'lar bilan ko'proq amaliyot qilishni xohlasangiz, AI tutor bilan suhbatlashing va quyidagi prompt'dan boshlang:

Mustahkamroq va tuzilmaliroq o'rganish yo'li uchun Python roadmap'ini ham ko'rib chiqishingiz mumkin.

Yo'l xaritalariQo'llanmalarFAQYouTube

yo'lxaritaroadmap.shasosida

Hamjamiyat tomonidan yaratilgan yo'l xaritalari, eng yaxshi amaliyotlar, loyihalar, maqolalar, manbalar va yo'nalishlar — o'z yo'lingizni tanlash va kasbingizda o'sish uchun.

© yo'lxarita·Shartlar·Maxfiylik·

roadmap.sh

Barcha kontent roadmap.sh loyihasidan olingan (© Kamran Ahmed) va shaxsiy o'rganish uchun o'zbek tiliga tarjima qilinmoqda.

Qidiruv

Yo'l xaritalari, loyihalar va savollarni qidiring