Trả lời nhanh
Với danh sách Python A, gọi n = len(A). Nếu n lẻ, xoá đúng một phần tử ở chỉ số n // 2. Nếu n chẵn, xoá đúng hai phần tử ở chỉ số n // 2 − 1 và n // 2. Cách chắc là del theo chỉ số. Dãy mẫu [1, 2, 2, 4, 5, 5] còn [1, 2, 5, 5]. Một số lời giải đang lưu hành lệch một chỉ số, gọi phương thức delete không có trong Python, hoặc dùng remove theo giá trị nên xoá nhầm khi dãy có số trùng.
Đề bài Luyện tập 2 trang 118
Bài nằm trong Bài 23. Một số lệnh làm việc với dữ liệu danh sách, Tin học 10, sách Kết nối tri thức. Đề yêu cầu: cho trước dãy số A, viết chương trình thực hiện hai việc. Nếu số phần tử là số lẻ thì xoá một phần tử ở chính giữa dãy. Nếu số phần tử là số chẵn thì xoá hai phần tử ở chính giữa dãy.
Đề không đưa sẵn một dãy cố định. Chương trình phải đúng với mọi A không rỗng. Vì vậy em không viết lệnh xoá “số 3” hay “số 4”, mà phải tính vị trí giữa từ độ dài của chính dãy đó. Danh sách trong Python đếm chỉ số từ 0: phần tử đầu là A[0], phần tử cuối là A[n − 1].
Cùng trang sách còn có bài chèn số bằng insert. Đó là việc khác. insert(k, x) nhét thêm phần tử, không xoá. Đừng trộn hai bài: bài này chỉ xoá phần tử giữa.
Cách xác định phần tử chính giữa
Chia độ dài cho 2 theo phép chia lấy phần nguyên. Với n lẻ, chỉ số giữa là n // 2. Đó cũng là phần tử thứ (n // 2 + 1) nếu đếm từ 1. Ví dụ n = 5, chỉ số giữa là 2, tức phần tử thứ 3.

Với n chẵn không có một “ô giữa” duy nhất. Hai ô giữa là cặp đứng sát tâm: chỉ số n // 2 − 1 và n // 2. Ví dụ n = 6 thì hai chỉ số là 2 và 3. Nhìn dãy [1, 2, 2, 4, 5, 5], hai giá trị bị xoá là 2 (số 2 thứ hai) và 4, còn lại [1, 2, 5, 5].
| n | Tính chất | Chỉ số bị xoá | Ví dụ A | A sau khi xoá |
|---|---|---|---|---|
| 5 | lẻ | 2 | 8, 1, 6, 3, 9 | 8, 1, 3, 9 |
| 6 | chẵn | 2 và 3 | 1, 2, 2, 4, 5, 5 | 1, 2, 5, 5 |
| 4 | chẵn | 1 và 2 | 5, 6, 7, 8 | 5, 8 |
| 1 | lẻ | 0 | 7 | danh sách rỗng |
Quy tắc nhớ nhanh: đếm số ô. Lẻ thì gạch một ô ở giữa. Chẵn thì gạch hai ô kề nhau sao cho bên trái và bên phải còn lại bằng nhau. Với 6 ô, mỗi bên còn 2 ô, đúng như mẫu [1, 2] và [5, 5].
Chương trình đúng
Đoạn sau sửa ngay trên danh sách A rồi in kết quả. Phép cắt del A[a:b] xoá từ chỉ số a đến trước b, nên một lệnh xoá được cả hai phần tử giữa.
n = len(A)
if n % 2 == 1:
del A[n // 2]
else:
del A[n // 2 – 1 : n // 2 + 1]
print(A)
Chạy với A = [1, 2, 2, 4, 5, 5]. n = 6, 6 % 2 bằng 0 nên vào nhánh chẵn. n // 2 − 1 = 2, n // 2 + 1 = 4, lệnh del A[2:4] bỏ A[2] và A[3]. In ra [1, 2, 5, 5].
Chạy với A = [8, 1, 6, 3, 9]. n = 5, 5 % 2 khác 0, del A[2] bỏ số 6. In ra [8, 1, 3, 9].
Nếu em thích pop, với dãy chẵn phải bỏ chỉ số lớn trước, vì mỗi lần xoá thì các chỉ số phía sau bị kéo lên:
if n % 2 == 1:
A.pop(n // 2)
else:
A.pop(n // 2)
A.pop(n // 2 – 1)
Xoá chỉ số nhỏ trước rồi mới xoá chỉ số cũ của phần tử kia sẽ lệch: phần tử thứ hai đã dồn sang trái, chỉ số cũ không còn trỏ đúng chỗ.
Vì sao một số lời giải ra sai
Các lời giải công bố không thống nhất. Ba dạng dưới đây không nên chép.
Gọi A.delete. Danh sách Python không có phương thức delete. Chạy sẽ báo lỗi thuộc tính. Lệnh xoá theo vị trí là del hoặc pop.
Lệch một chỉ số. Có lời giải xoá A[n // 2 + 1] khi n lẻ. Với n = 5, n // 2 + 1 = 3, tức số 3 trong dãy [8, 1, 6, 3, 9], trong khi phần tử giữa phải là 6. Lỗi này thường do trộn cách đếm từ 1 với chỉ số từ 0.
Dùng remove theo giá trị. A.remove(x) tìm giá trị x và xoá lần xuất hiện đầu tiên, không xoá theo ô em chỉ. Thử A = [9, 1, 9, 4, 5, 6]. Hai phần tử giữa là số 9 ở chỉ số 2 và số 4 ở chỉ số 3. Kết quả đúng là [9, 1, 5, 6]. Nếu viết remove(A[3]) rồi remove(A[2]) sau khi dãy đã ngắn lại, lần sau remove gặp giá trị 9 và xoá số 9 đầu tiên, còn [1, 9, 5, 6]. Sai, dù chương trình không báo lỗi.
Mẫu [1, 2, 2, 4, 5, 5] dễ làm em tưởng remove đúng, vì hai số 2 giống nhau nên xoá nhầm số 2 nào cũng in ra [1, 2, 5, 5]. Hãy thử thêm một dãy có giá trị lặp ở hai đầu, như [9, 1, 9, 4, 5, 6], trước khi nộp bài.
Bài tập tự kiểm tra
Bài 1. A = [4, 7, 1]. Nêu A sau khi chạy chương trình đúng.
Đáp án: n = 3, xoá chỉ số 1, còn [4, 1].
Bài 2. A = [5, 6, 7, 8]. Nêu hai chỉ số bị xoá và dãy còn lại.
Đáp án: chỉ số 1 và 2, tức 6 và 7. Còn [5, 8].
Bài 3. A = [9, 1, 9, 4, 5, 6]. Vì sao A.remove(9) không thay được cho việc xoá phần tử giữa?
Đáp án: remove(9) xoá số 9 ở đầu dãy, tức A[0], không phải số 9 ở chỉ số 2. Phần tử giữa của dãy chẵn này là A[2] và A[3].
Khi viết bài, em nên in A trước và sau khi xoá với ít nhất ba trường hợp: n lẻ, n chẵn, và một dãy có số trùng. Ba lần in đó đủ để bắt lỗi chỉ số và lỗi remove.
Câu hỏi thường gặp
Chỉ số chính giữa của danh sách Python tính thế nào?
Nếu len(A) lẻ, chỉ số giữa là len(A) // 2. Nếu chẵn, hai chỉ số giữa là len(A) // 2 - 1 và len(A) // 2. Chỉ số bắt đầu từ 0.
Vì sao không dùng A.remove để xoá phần tử giữa?
remove xoá theo giá trị và chỉ xoá lần xuất hiện đầu tiên. Khi dãy có số trùng, nó có thể xoá nhầm phần tử không nằm giữa.
A.delete có dùng được không?
Không. Danh sách Python không có phương thức delete. Xoá theo vị trí bằng del hoặc pop.
Dãy [1, 2, 2, 4, 5, 5] sau khi xoá còn gì?
Còn [1, 2, 5, 5]. Hai phần tử giữa bị xoá là số 2 ở chỉ số 2 và số 4 ở chỉ số 3.
Xoá hai phần tử giữa thì phải xoá chỉ số nào trước?
Nếu xoá từng phần tử, hãy xoá chỉ số lớn hơn trước, rồi mới xoá chỉ số nhỏ. Xoá chỉ số nhỏ trước sẽ làm chỉ số còn lại bị lệch.