Bài 7: Dictionaries - Từ Điển (Phần 1)

Mục Tiêu Bài Học

Sau khi hoàn thành bài này, bạn sẽ:

  • ✅ Hiểu dictionary là gì và key-value pairs
  • ✅ Tạo và truy cập dictionary
  • ✅ Thêm, xóa, sửa phần tử trong dict
  • ✅ Sử dụng dictionary methods cơ bản
  • ✅ Iterate through dictionaries

Dictionary Là Gì?

Dictionary (dict) là collection lưu trữ dữ liệu dạng key-value pairs (cặp khóa-giá trị). Dictionary là unordered (Python 3.7+ giữ insertion order), mutable, và không cho phép key trùng.

# Dictionary với dấu ngoặc nhọn {}person = {    "name": "Alice",    "age": 25,    "email": "[email protected]"} print(type(person))  # <class 'dict'>

Key-Value Pairs:

# Syntax: {key: value, key: value, ...}student = {    "id": 101,           # key: "id", value: 101    "name": "Bob",       # key: "name", value: "Bob"    "grade": 85,         # key: "grade", value: 85    "passed": True       # key: "passed", value: True} # Key phải là immutable (string, number, tuple)# Value có thể là bất kỳ kiểu gì

So sánh với List:

# List - truy cập bằng index (số)fruits = ["apple", "banana", "orange"]print(fruits[0])  # apple # Dictionary - truy cập bằng key (string, number, ...)fruit_prices = {    "apple": 2.5,    "banana": 1.5,    "orange": 3.0}print(fruit_prices["apple"])  # 2.5

Tạo Dictionary

Cách 1: Dùng Dấu Ngoặc Nhọn {}

# Empty dictionaryempty_dict = {}print(type(empty_dict))  # <class 'dict'> # Dictionary với dataperson = {    "name": "Alice",    "age": 25,    "city": "Hanoi"} # Mixed value typesmixed = {    "string": "Hello",    "number": 42,    "float": 3.14,    "bool": True,    "list": [1, 2, 3],    "dict": {"nested": "value"}} # Multi-line (readable)user = {    "username": "alice123",    "email": "[email protected]",    "is_active": True,    "roles": ["user", "admin"]}

Cách 2: dict() Constructor

# Từ keyword argumentsperson = dict(name="Bob", age=30, city="HCMC")print(person)  # {'name': 'Bob', 'age': 30, 'city': 'HCMC'} # Từ list of tuplespairs = [("a", 1), ("b", 2), ("c", 3)]my_dict = dict(pairs)print(my_dict)  # {'a': 1, 'b': 2, 'c': 3} # Từ 2 lists (zip)keys = ["name", "age", "city"]values = ["Charlie", 35, "Danang"]person = dict(zip(keys, values))print(person)  # {'name': 'Charlie', 'age': 35, 'city': 'Danang'}

Cách 3: Dictionary Comprehension

# Tạo dict từ rangesquares = {x: x**2 for x in range(5)}print(squares)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} # Với điều kiệnevens = {x: x**2 for x in range(10) if x % 2 == 0}print(evens)  # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64} # Từ listfruits = ["apple", "banana", "orange"]fruit_lengths = {f: len(f) for f in fruits}print(fruit_lengths)  # {'apple': 5, 'banana': 6, 'orange': 6}

Truy Cập Phần Tử

Dùng [] (Square Brackets)

person = {    "name": "Alice",    "age": 25,    "email": "[email protected]"} # Truy cập value bằng keyprint(person["name"])   # Aliceprint(person["age"])    # 25 # Lỗi nếu key không tồn tại# print(person["phone"])  # KeyError: 'phone'

Dùng get() Method (An toàn hơn)

person = {    "name": "Alice",    "age": 25} # get(key) - trả về None nếu key không tồn tạiphone = person.get("phone")print(phone)  # None # get(key, default) - trả về default nếu key không tồn tạiphone = person.get("phone", "N/A")print(phone)  # N/A # So sánhprint(person["name"])        # Aliceprint(person.get("name"))    # Alice # print(person["phone"])     # KeyError!print(person.get("phone"))   # None (không lỗi)

Nested Dictionaries

# Dictionary chứa dictionarycompany = {    "name": "Tech Corp",    "employees": {        "alice": {"age": 25, "role": "Developer"},        "bob": {"age": 30, "role": "Manager"}    }} # Truy cập nestedprint(company["name"])                    # Tech Corpprint(company["employees"]["alice"])      # {'age': 25, 'role': 'Developer'}print(company["employees"]["alice"]["age"])  # 25 # An toàn với get()role = company.get("employees", {}).get("alice", {}).get("role")print(role)  # Developer

Thay Đổi Dictionary

Thêm/Sửa Phần Tử

person = {    "name": "Alice",    "age": 25} # Thêm key mớiperson["email"] = "[email protected]"print(person)# {'name': 'Alice', 'age': 25, 'email': '[email protected]'} # Sửa value (key đã tồn tại)person["age"] = 26print(person)# {'name': 'Alice', 'age': 26, 'email': '[email protected]'} # Key không tồn tại -> thêm mới# Key đã tồn tại -> updateperson["city"] = "Hanoi"  # Thêmperson["city"] = "HCMC"   # Update

update() Method

person = {    "name": "Alice",    "age": 25} # Update từ dict khácperson.update({"email": "[email protected]", "phone": "123456"})print(person)# {'name': 'Alice', 'age': 25, 'email': '[email protected]', 'phone': '123456'} # Update với keyword argumentsperson.update(age=26, city="Hanoi")print(person) # Nếu key đã tồn tại -> update# Nếu key chưa có -> thêm mớiperson.update({"age": 27, "country": "Vietnam"})

Xóa Phần Tử

person = {    "name": "Alice",    "age": 25,    "email": "[email protected]",    "phone": "123456"} # 1. del - xóa theo keydel person["phone"]print(person)  # phone đã bị xóa # Lỗi nếu key không tồn tại# del person["address"]  # KeyError! # 2. pop() - xóa và trả về valueemail = person.pop("email")print(email)   # [email protected]print(person)  # email đã bị xóa # pop với default (không lỗi nếu key không tồn tại)phone = person.pop("phone", "N/A")print(phone)  # N/A # 3. popitem() - xóa và trả về (key, value) cuối cùngitem = person.popitem()print(item)    # ('age', 25)print(person)  # {'name': 'Alice'} # 4. clear() - xóa tất cảperson.clear()print(person)  # {}

Dictionary Methods

keys(), values(), items()

person = {    "name": "Alice",    "age": 25,    "email": "[email protected]"} # keys() - lấy tất cả keyskeys = person.keys()print(keys)  # dict_keys(['name', 'age', 'email'])print(list(keys))  # ['name', 'age', 'email'] # values() - lấy tất cả valuesvalues = person.values()print(values)  # dict_values(['Alice', 25, '[email protected]'])print(list(values))  # ['Alice', 25, '[email protected]'] # items() - lấy tất cả (key, value) pairsitems = person.items()print(items)# dict_items([('name', 'Alice'), ('age', 25), ('email', '[email protected]')])print(list(items))# [('name', 'Alice'), ('age', 25), ('email', '[email protected]')]

in Operator - Check Key

person = {    "name": "Alice",    "age": 25} # Check key tồn tạiprint("name" in person)    # Trueprint("email" in person)   # Falseprint("age" not in person) # False # ⚠️ in chỉ check key, không check value!print("Alice" in person)   # False (Alice là value, không phải key)print("Alice" in person.values())  # True (check trong values)

copy() - Sao Chép

original = {    "name": "Alice",    "age": 25} # Shallow copycopy1 = original.copy()copy1["age"] = 30print(original)  # {'name': 'Alice', 'age': 25} (không đổi)print(copy1)     # {'name': 'Alice', 'age': 30} # Reference (KHÔNG phải copy!)ref = originalref["age"] = 30print(original)  # {'name': 'Alice', 'age': 30} (đã đổi!) # Deep copy (nested dictionaries)import copynested = {    "name": "Bob",    "contact": {"email": "[email protected]"}} shallow = nested.copy()shallow["contact"]["email"] = "[email protected]"print(nested["contact"]["email"])  # [email protected] (bị đổi!) deep = copy.deepcopy(nested)deep["contact"]["email"] = "[email protected]"print(nested["contact"]["email"])  # [email protected] (không đổi)

setdefault() - Lấy hoặc Set Default

person = {    "name": "Alice"} # Nếu key tồn tại -> trả về valuename = person.setdefault("name", "Unknown")print(name)  # Alice # Nếu key không tồn tại -> thêm với default valueage = person.setdefault("age", 0)print(age)     # 0print(person)  # {'name': 'Alice', 'age': 0} # So sánh với get()# get() - không thêm key mớiemail = person.get("email", "N/A")print(email)   # N/Aprint(person)  # {'name': 'Alice', 'age': 0} (không có email) # setdefault() - thêm key mới nếu chưa cóemail = person.setdefault("email", "[email protected]")print(email)   # [email protected]print(person)  # {'name': 'Alice', 'age': 0, 'email': '[email protected]'}

Iterate Through Dictionary

Loop Through Keys

person = {    "name": "Alice",    "age": 25,    "city": "Hanoi"} # Default - loop through keysfor key in person:    print(key)# name# age# city # Explicit - keys()for key in person.keys():    print(key, "->", person[key])# name -> Alice# age -> 25# city -> Hanoi

Loop Through Values

person = {    "name": "Alice",    "age": 25,    "city": "Hanoi"} # values()for value in person.values():    print(value)# Alice# 25# Hanoi

Loop Through Items (Key-Value)

person = {    "name": "Alice",    "age": 25,    "city": "Hanoi"} # items() - recommendedfor key, value in person.items():    print(f"{key}: {value}")# name: Alice# age: 25# city: Hanoi # Format đẹpfor key, value in person.items():    print(f"{key:<10} = {value}")# name       = Alice# age        = 25# city       = Hanoi

Ví Dụ Thực Tế

1. Phone Book

# Danh bạ điện thoạiphonebook = {    "Alice": "0123456789",    "Bob": "0987654321",    "Charlie": "0111222333"} # Thêm contactphonebook["Diana"] = "0444555666" # Tìm số điện thoạiname = "Alice"phone = phonebook.get(name, "Not found")print(f"{name}'s phone: {phone}") # Update sốphonebook["Bob"] = "0999888777" # Xóa contactphonebook.pop("Charlie", None) # Hiển thị toàn bộprint("\nPhone Book:")for name, phone in phonebook.items():    print(f"  {name:<15} {phone}")

2. Inventory System

# Kho hànginventory = {    "apple": {"quantity": 50, "price": 2.5},    "banana": {"quantity": 30, "price": 1.5},    "orange": {"quantity": 40, "price": 3.0}} # Hiển thị inventoryprint("Inventory:")for item, info in inventory.items():    qty = info["quantity"]    price = info["price"]    total = qty * price    print(f"  {item.capitalize():<10} Qty: {qty:>3}  Price: ${price:>5.2f}  Total: ${total:>6.2f}") # Bán hàngdef sell_item(item, quantity):    if item in inventory:        if inventory[item]["quantity"] >= quantity:            inventory[item]["quantity"] -= quantity            print(f"Sold {quantity} {item}(s)")        else:            print(f"Not enough {item}!")    else:        print(f"{item} not in inventory!") sell_item("apple", 10)sell_item("banana", 50)  # Not enough # Thêm hàng mớiinventory["grape"] = {"quantity": 20, "price": 4.0}

3. Word Frequency Counter

text = """Python is an amazing programming language.Python is easy to learn and Python is powerful.""" # Xử lý textwords = text.lower().split()words = [w.strip('.,!?') for w in words] # Đếm frequencyword_count = {}for word in words:    word_count[word] = word_count.get(word, 0) + 1 # Hiển thịprint("Word Frequency:")for word, count in sorted(word_count.items(), key=lambda x: x[1], reverse=True):    print(f"  {word:<15} {count}") # Top 3 wordstop_3 = sorted(word_count.items(), key=lambda x: x[1], reverse=True)[:3]print("\nTop 3 words:")for word, count in top_3:    print(f"  {word}: {count}")

4. Student Grade System

# Điểm học sinhstudents = {    "Alice": [85, 90, 88],    "Bob": [78, 82, 80],    "Charlie": [92, 95, 90],    "Diana": [88, 85, 87]} # Tính điểm trung bìnhprint("Student Grades:")for name, grades in students.items():    avg = sum(grades) / len(grades)    print(f"  {name:<10} Grades: {grades}  Average: {avg:.2f}") # Tìm học sinh cao điểm nhấtbest_student = max(students.items(), key=lambda x: sum(x[1]) / len(x[1]))best_name, best_grades = best_studentbest_avg = sum(best_grades) / len(best_grades)print(f"\nBest student: {best_name} with average {best_avg:.2f}") # Thêm điểm mớistudents["Alice"].append(95)print(f"\nAlice's new grades: {students['Alice']}") # Học sinh pass (average >= 80)passed = {name: grades for name, grades in students.items()           if sum(grades) / len(grades) >= 80}print(f"\nPassed students: {list(passed.keys())}")

5. Config Settings

# Application configconfig = {    "app_name": "My App",    "version": "1.0.0",    "debug": True,    "database": {        "host": "localhost",        "port": 5432,        "name": "mydb"    },    "features": {        "auth": True,        "email": True,        "notifications": False    }} # Access nested configdb_host = config["database"]["host"]print(f"Database host: {db_host}") # Check feature enabledif config["features"]["auth"]:    print("Authentication enabled") # Update configconfig["debug"] = Falseconfig["database"]["port"] = 3306 # Display configprint("\nConfiguration:")for key, value in config.items():    if isinstance(value, dict):        print(f"{key}:")        for k, v in value.items():            print(f"  {k}: {v}")    else:        print(f"{key}: {value}")

Bài Tập Thực Hành

Bài 1: Basic Operations

Tạo dictionary student với name, age, grade:

  • Thêm email
  • Update age
  • Xóa grade
  • Hiển thị tất cả keys và values

Bài 2: Merge Dictionaries

Gộp 2 dictionaries:

  • dict1 = {"a": 1, "b": 2}
  • dict2 = {"b": 3, "c": 4}
  • Result: {"a": 1, "b": 3, "c": 4}

Bài 3: Reverse Dictionary

Đảo key-value:

  • Input: {"a": 1, "b": 2, "c": 3}
  • Output: {1: "a", 2: "b", 3: "c"}

Bài 4: Group By

Cho list students, group theo grade:

  • Students: [("Alice", "A"), ("Bob", "B"), ("Charlie", "A")]
  • Result: {"A": ["Alice", "Charlie"], "B": ["Bob"]}

Bài 5: Shopping Cart

Tạo shopping cart với:

  • Add item (name, price, quantity)
  • Update quantity
  • Remove item
  • Calculate total

Tóm Tắt

✅ Dictionary: key-value pairs, unordered (3.7+ ordered), mutable
✅ Access: dict[key] hoặc dict.get(key, default)
✅ Add/Update: dict[key] = value hoặc dict.update()
✅ Remove: del, pop(), popitem(), clear()
✅ Methods: keys(), values(), items(), get(), setdefault()
✅ Loop: for key, value in dict.items()
✅ Check: key in dict

Bài Tiếp Theo

Bài 7.2: Dictionaries (Phần 2) - Dictionary comprehension, defaultdict, Counter, và advanced techniques.


Remember:

  • Keys phải immutable (string, number, tuple)
  • get() an toàn hơn [] khi key có thể không tồn tại
  • items() để loop qua key-value pairs
  • Dictionary rất nhanh cho lookups (O(1))
  • Dùng dictionaries cho mappings, configs, counters!