Đếm Số Nguyên Trong List Python: Phân Loại Âm, Dương, 0
Đếm Số Nguyên Trong List Python: Phân Loại Âm, Dương, 0

Đếm số nguyên trong một danh sách (list) là bài toán nền tảng giúp lập trình viên làm quen với tư duy rẽ nhánh và kiểm soát luồng dữ liệu. Thay vì chỉ viết một đoạn code chạy được, bài viết này sẽ hướng dẫn bạn cách phân loại chính xác số lượng các số âm, dương và số 0, đồng thời xử lý an toàn các phần tử “rác” không hợp lệ — một kỹ năng bắt buộc đối với sinh viên năm nhất khi bước vào các dự án thực tế.

💡 Trả lời nhanh: Để đếm số nguyên âm, số dương và số 0, bạn khởi tạo 3 biến đếm (hoặc 1 Dictionary). Sử dụng vòng lặp for để duyệt qua list, kết hợp hàm isinstance() để lọc loại bỏ chuỗi/dữ liệu rỗng, sau đó dùng if-elif-else để kiểm tra điều kiện > 0, < 0, == 0 và tăng biến đếm tương ứng.


Đề bài 

Bạn được cung cấp một danh sách (list) có thể chứa nhiều kiểu dữ liệu khác nhau (số nguyên, chuỗi văn bản, giá trị rỗng). Yêu cầu đặt ra như sau:

Input: Một list chứa các phần tử bất kỳ. Ví dụ: [1, -2, 0, 5, 'text', -3, 0, None, True]

Output: Số lượng đếm được chia làm 3 nhóm: số nguyên âm, số nguyên dương và số 0.

Ràng buộc: – Phải bỏ qua (không đếm) các phần tử không phải là số nguyên (như string, NoneType).

  • Cần chú ý xử lý kiểu dữ liệu Boolean vì trong Python, TrueFalse mặc định được coi là 1 và 0 dưới nền tảng.


Phân tích bài toán đếm số nguyên âm và đếm số nguyên dương 

Để đếm số nguyên âm, số nguyên dương và số 0 trong Python, chúng ta cần duyệt qua danh sách và sử dụng cấu trúc rẽ nhánh if-elif-else kết hợp với toán tử so sánh > 0, < 0== 0.

Bản chất của bài toán này không nằm ở việc bạn biết dùng vòng lặp hay không, mà nằm ở khả năng “làm sạch dữ liệu” (Data Cleaning) trước khi đưa vào tính toán. Nếu danh sách của bạn chỉ toàn các con số hoàn hảo, bài toán là ở mức cơ bản. Tuy nhiên, khi nâng lên mức độ trung cấp, hệ thống đòi hỏi mã nguồn của bạn phải đủ sức chịu đựng các dữ liệu đầu vào không mong muốn mà không bị sập (crash).

📌 Góc nhìn thực tế: Trong thực tế làm dự án hoặc chấm bài thi thực hành, sinh viên thường hay mất điểm oan ở lỗi TypeError. Lỗi này xảy ra khi các bạn mang một chuỗi văn bản (ví dụ chữ “text”) đi so sánh xem nó lớn hơn hay nhỏ hơn 0. Trình thông dịch của Python sẽ lập tức báo lỗi và dừng toàn bộ chương trình.

Giả định của chúng ta

Trong bài hướng dẫn này, chúng ta giả định rằng danh sách đầu vào là dữ liệu hỗn hợp (mixed data). Điều này có nghĩa là list có thể chứa string, float, kiểu None, hoặc các list con bên trong. Do đó, bước kiểm tra kiểu dữ liệu bằng hàm built-in của Python là điều kiện kiên quyết trước khi rẽ nhánh.

Chính vì những đặc điểm trên, chúng ta sẽ tiếp cận bài toán bằng hai phương pháp. Phương pháp đầu tiên tập trung vào tư duy thuật toán rành mạch cho người mới. Phương pháp thứ hai tập trung vào cách viết code chuyên nghiệp (Pythonic) tối ưu để tích hợp vào các hệ thống lớn.


Cách 1: Đếm số nguyên bằng vòng lặp for và 3 biến đếm 

Cách 1 sử dụng vòng lặp for truyền thống kết hợp với 3 biến đếm rời rạc, rất phù hợp với sinh viên năm 1 để rèn luyện tư duy rẽ nhánh và kiểm soát luồng dữ liệu một cách trực quan nhất.

Ý tưởng cốt lõi

Chúng ta sẽ chuẩn bị sẵn 3 chiếc “hộp” (biến đếm) có giá trị ban đầu bằng 0, tượng trưng cho: số âm, số dương và số không. Khi duyệt qua từng phần tử trong danh sách, chúng ta làm một trạm kiểm duyệt:

  1. Đầu tiên, kiểm tra xem phần tử đó có phải là số nguyên thực thụ hay không.

  2. Nếu không phải, lập tức bỏ qua và đi đến phần tử tiếp theo.

  3. Nếu đúng là số nguyên, ta tiến hành hỏi: Nó lớn hơn 0, nhỏ hơn 0, hay bằng 0? Tùy vào câu trả lời mà thả 1 đơn vị vào chiếc “hộp” tương ứng.

Các bước thực hiện

  1. Khởi tạo 3 biến: dem_am = 0, dem_duong = 0, dem_khong = 0.

  2. Mở một vòng lặp for x in danh_sach: để duyệt từng phần tử.

  3. Kiểm tra kiểu dữ liệu: Nếu type(x) is int (chỉ chấp nhận số nguyên thuần túy, loại trừ cả boolean do boolean kế thừa từ int).

  4. Áp dụng if x > 0: tăng dem_duong lên 1.

  5. Áp dụng elif x < 0: tăng dem_am lên 1.

  6. Áp dụng else: (trường hợp chắc chắn x == 0), tăng dem_khong lên 1.

  7. Đóng vòng lặp và trả về một tuple chứa 3 giá trị trên.

Minh họa tay (Trace logic)

Hãy thử nháp tay với input: [1, 'a', 0, -5]

  • Khởi tạo: dem_am = 0, dem_duong = 0, dem_khong = 0

  • Bước 1 (x = 1): Là int. 1 > 0 -> dem_duong = 1.

  • Bước 2 (x = ‘a’): Không phải int. Bỏ qua.

  • Bước 3 (x = 0): Là int. Không > 0, không < 0 -> Nhảy vào else -> dem_khong = 1.

  • Bước 4 (x = -5): Là int. -5 < 0 -> dem_am = 1.

  • Kết quả trả về: (1, 1, 1)

Đánh giá

  • Phù hợp người mới vì: Logic tách bạch, từng dòng code đều thể hiện rõ ràng tiếng Việt đang nghĩ gì thì code viết như thế. Dễ dàng dùng lệnh print() ở giữa các bước để gỡ lỗi (debug).

  • Ưu điểm: Dễ hiểu, dễ bảo trì đối với các bài tập môn nhập môn lập trình.

  • Nhược điểm: Trả về nhiều biến rời rạc, nếu bài toán mở rộng thêm đếm số chẵn, số lẻ, số nguyên tố… thì số lượng biến sẽ phình to rất nhanh và khó quản lý.

  • Độ phức tạp: O(N) thời gian (duyệt mảng đúng 1 lần) / O(1) bộ nhớ (chỉ tốn 3 biến đếm cố định, không phụ thuộc độ dài list).

Để giải quyết nhược điểm về sự cồng kềnh của biến đếm, chúng ta sẽ chuyển sang một cấu trúc dữ liệu mạnh mẽ hơn ở phần tiếp theo.


Cách 2: Gom nhóm đếm số nguyên vào Dictionary

Khác với Cách 1, cách này gom toàn bộ kết quả phân loại đếm số nguyên vào một cấu trúc dữ liệu Dictionary duy nhất, giúp mã nguồn trở nên chuyên nghiệp, gọn gàng và dễ dàng mở rộng.

Ý tưởng thuật toán

Thay vì xách theo 3 chiếc giỏ rời rạc, chúng ta tạo một chiếc tủ có 3 ngăn (tương ứng với 3 keys trong Dictionary). Mỗi khi đọc được một con số, ta đối chiếu điều kiện và cập nhật trực tiếp giá trị (value) của ngăn tủ đó. Đây là tư duy “nhóm dữ liệu” rất phổ biến khi bạn làm việc với JSON hoặc các API trả về dữ liệu cho Front-end.

Các bước thực hiện

  1. Khởi tạo một Dictionary: ket_qua = {'am': 0, 'duong': 0, 'khong': 0}.

  2. Dùng vòng lặp for để duyệt qua từng phần tử x trong danh sách.

  3. Dùng hàm isinstance(x, int)not isinstance(x, bool) để sàng lọc dữ liệu nghiêm ngặt.

  4. Nếu x > 0, truy cập và cập nhật: ket_qua['duong'] += 1.

  5. Nếu x < 0, cập nhật: ket_qua['am'] += 1.

  6. Nếu x == 0, cập nhật: ket_qua['khong'] += 1.

  7. Trả về toàn bộ Dictionary ket_qua.

Minh họa tay

Input: [1, 'a', 0, -5]

  • Khởi tạo: ket_qua = {'am': 0, 'duong': 0, 'khong': 0}

  • Bước 1 (x = 1): Số nguyên hợp lệ. > 0. ket_qua['duong'] tăng thành 1.

  • Bước 2 (x = ‘a’): Bị loại ở màng lọc type.

  • Bước 3 (x = 0): Số nguyên hợp lệ. == 0. ket_qua['khong'] tăng thành 1.

  • Bước 4 (x = -5): Số nguyên hợp lệ. < 0. ket_qua['am'] tăng thành 1.

  • Kết quả trả về: {'am': 1, 'duong': 1, 'khong': 1}.

Khi nào nên dùng Cách 2?

Bạn nên sử dụng cách này khi đang xây dựng một hàm (function) là một phần của hệ thống lớn hơn. Ví dụ, hàm này cung cấp dữ liệu cho một biểu đồ thống kê trên web. Biểu đồ đó cần nhận một đối tượng JSON có sẵn các nhãn (labels) ‘am’, ‘duong’ rõ ràng chứ không phải là một tuple chứa những con số ẩn danh.

Đánh giá

  • Ưu điểm: Code sạch sẽ (clean code), chuẩn phong cách Pythonic. Cực kỳ dễ mở rộng. Trả về dữ liệu có cấu trúc ngữ nghĩa cao (Semantic data structure).

  • Nhược điểm: Với những người mới học những buổi đầu tiên, cú pháp truy cập Dictionary dict[key] += 1 có thể hơi lạ lẫm so với bien += 1.

  • Độ phức tạp: O(N) thời gian / O(1) bộ nhớ.


So sánh nhanh 2 cách 

Bảng này giúp bạn quyết định nên dùng cách nào để viết code đếm số nguyên mà không cần đọc lại toàn bài.

Tiêu chí Cách 1: Vòng lặp for & Biến đếm Cách 2: Cấu trúc Dictionary
Ý tưởng cốt lõi Dùng 3 biến độc lập để lưu trữ kết quả rẽ nhánh Lưu chung vào 1 từ điển (dict) với 3 khóa (keys) định danh
Độ phức tạp O(N) thời gian / O(1) không gian O(N) thời gian / O(1) không gian
Dễ đọc / dễ hiểu ★★★★★ ★★★★☆
Tính chuyên nghiệp ★★★☆☆ ★★★★★
Phù hợp khi Mới học lập trình, cần hiểu sâu về cơ chế rẽ nhánh Cần trả kết quả API, thao tác dự án thực tế
Không phù hợp khi Cần gom nhóm nhiều hơn 5 loại điều kiện phân loại Học sinh chưa nắm vững cú pháp Key-Value

Code Python đếm số nguyên đầy đủ 

Đếm Số Nguyên Trong List Python: Phân Loại Âm, Dương, 0
Đếm Số Nguyên Trong List Python: Phân Loại Âm, Dương, 0

Cách 1 — Dùng vòng lặp for và 3 biến đếm rời rạc:

# Đếm số nguyên âm, dương, 0 với 3 biến rời rạc

def dem_so_nguyen_cach1(danh_sach):
    """
    Hàm nhận vào một list, đếm số lượng số nguyên âm, dương và 0.
    Trả về một tuple (số_âm, số_dương, số_không).
    """
    dem_am = 0
    dem_duong = 0
    dem_khong = 0
    
    for x in danh_sach:
        # Bắt buộc kiểm tra: x phải là int VÀ không phải là boolean
        # (Vì trong Python, True == 1, False == 0)
        if type(x) is int and type(x) is not bool:
            if x > 0:
                dem_duong += 1
            elif x < 0:
                dem_am += 1
            else:
                dem_khong += 1
                
    return dem_am, dem_duong, dem_khong

# --- TEST NHANH ---
# input_list = [1, -2, 0, 5, 'text', -3, 0, None, True]
# am, duong, khong = dem_so_nguyen_cach1(input_list)
# print(f"Âm: {am}, Dương: {duong}, Không: {khong}")

Cách 2 — Gom kết quả bằng cấu trúc Dictionary:

# Điểm khác với Cách 1: Sử dụng Dictionary để cấu trúc hóa dữ liệu trả về

def dem_so_nguyen_cach2(danh_sach):
    """Hàm đếm số nguyên sử dụng Dictionary."""
    ket_qua = {'am': 0, 'duong': 0, 'khong': 0}
    
    for x in danh_sach:
        # Cách viết chuẩn dùng isinstance() kết hợp lọc type bool
        if isinstance(x, int) and not isinstance(x, bool):
            if x > 0:
                ket_qua['duong'] += 1
            elif x < 0:
                ket_qua['am'] += 1
            else:
                ket_qua['khong'] += 1
                
    return ket_qua
# --- TEST NHANH ---
# input_list = [1, -2, 0, 5, 'text', -3, 0, None, True]
# print(dem_so_nguyen_cach2(input_list))

Ví dụ chạy thử 

Bảng output dưới đây tương ứng với mã nguồn Cách 2 (Dictionary) chạy trên môi trường Python 3.12.

STT Input Output (Cách 2) Giải thích
1 [5, 10, -2, 0] {'am': 1, 'duong': 2, 'khong': 1} Danh sách số nguyên tiêu chuẩn, hàm xử lý trơn tru không gặp rào cản.
2 ['1', 'a', None, 5.5] {'am': 0, 'duong': 0, 'khong': 0} Không có phần tử nào là số nguyên (int). Float 5.5 và String '1' bị bỏ qua theo đúng đề bài.
3 [0, -1, True, False] {'am': 1, 'duong': 0, 'khong': 1} Edge case (Trường hợp biên): True/False bị bộ lọc loại bỏ do chúng ta đã dùng not isinstance(x, bool). Nếu không lọc, True sẽ bị đếm nhầm thành 1 (dương).

Việc dự đoán và chặn trước các ngoại lệ (edge cases) là đặc điểm phân biệt giữa một sinh viên làm bài đối phó và một lập trình viên thực thụ. Dưới đây là các lỗi bạn chắc chắn sẽ vấp phải nếu bỏ qua bước làm sạch dữ liệu.


Lỗi thường gặp khi viết hàm đếm số nguyên

Lỗi 1: Chương trình văng lỗi TypeError do so sánh chuỗi

Khi danh sách đầu vào chứa các phần tử không phải là số (như string 'text'), việc ép buộc toán tử so sánh lớn nhỏ sẽ khiến trình thông dịch của Python báo lỗi: TypeError: '>' not supported between instances of 'str' and 'int'.

Nguyên nhân: Vì Python là ngôn ngữ định kiểu động (dynamic typing) nhưng lại “strongly typed”, nó không tự động chuyển đổi chữ cái thành số để so sánh. Toán tử > không hiểu phải làm gì giữa một chuỗi và số 0.

Code sai:

# output sai là: Chương trình crash (dừng đột ngột) báo lỗi TypeError
for x in danh_sach:
    if x > 0:  # Lỗi xảy ra ở dòng này nếu x là 'text'
        dem_duong += 1

Code đúng:

# output đúng là: Hàm chạy an toàn lướt qua các phần tử rác
for x in danh_sach:
    if isinstance(x, int): # Dựng khiên bảo vệ trước khi rẽ nhánh
        if x > 0:
            dem_duong += 1

Lỗi 2: Đếm sai số lượng số 0 (bỏ sót số 0)

Bạn viết hàm và phát hiện ra tổng số phần tử âm và dương cộng lại nhỏ hơn độ dài danh sách (dù danh sách chỉ toàn số nguyên). Số lượng số 0 luôn trả về 0 một cách bí ẩn.

Nguyên nhân: Vì bạn chỉ sử dụng cấu trúc rẽ nhánh if x > 0if x < 0 riêng biệt, mà không gom chúng vào chuỗi if-elif-else. Khi số 0 xuất hiện, nó không thỏa mãn hai lệnh if trên và trôi tuột đi mất mà không được cộng vào biến đếm nào.

Code sai:

# output sai là: dem_khong luôn bằng 0
if x > 0: dem_duong += 1
if x < 0: dem_am += 1
# Thiếu logic xử lý trường hợp x == 0

Code đúng:

# output đúng là: Đếm chính xác mọi trường hợp
if x > 0: 
    dem_duong += 1
elif x < 0: 
    dem_am += 1
else: # Bắt trọn trường hợp còn lại duy nhất là bằng 0
    dem_khong += 1

Lỗi 3: Lỗi KeyError khi dùng Dictionary

Khi sử dụng Cách 2, chương trình bỗng dưng báo lỗi KeyError: 'duong' ngay trong lần lặp đầu tiên tìm thấy số nguyên dương.

Nguyên nhân: Vì bạn đã khai báo một Dictionary rỗng (hoặc gõ sai chính tả key) nhưng lại cố gắng truy cập và cộng dồn giá trị vào một khóa (key) chưa từng tồn tại trong bộ nhớ.

Code sai:

# output sai là: Báo lỗi KeyError
ket_qua = {} # Dictionary trống
ket_qua['duong'] += 1 # Không thể cộng 1 vào hư vô

Code đúng:

# output đúng là: Cộng dồn bình thường
ket_qua = {'am': 0, 'duong': 0, 'khong': 0} # Khởi tạo giá trị nền
ket_qua['duong'] += 1 

Lỗi 4: Đếm nhầm kiểu dữ liệu Boolean thành số

Chương trình báo đếm được 1 số dương và 1 số 0, dù danh sách đầu vào của bạn chỉ là [True, False].

Nguyên nhân: Vì trong thiết kế lõi của Python, lớp bool là một lớp con (subclass) của lớp int. Do đó, True mang giá trị thực chất là 1, và False mang giá trị là 0. Nếu chỉ dùng isinstance(x, int) chung chung, True sẽ lọt qua khe cửa và đi thẳng vào nhánh đếm số dương.

Code sai:

# output sai là: đếm True là số dương, False là số không
if isinstance(x, int): 
    # Logic đếm...

Code đúng:

# output đúng là: Loại trừ hoàn toàn boolean khỏi cuộc chơi
if type(x) is int and type(x) is not bool:
    # Logic đếm...

Lỗi 5: Lỗi UnboundLocalError hoặc quên trả kết quả (None)

Hàm chạy không báo lỗi gì, nhưng khi bạn print() kết quả của hàm ra ngoài màn hình thì lại nhận được chữ None thay vì các con số.

Nguyên nhân: Vì bạn đã khai báo biến và thực hiện logic đếm hoàn hảo bên trong thân hàm, nhưng lại quên mất từ khóa lệnh return ở dòng cuối cùng. Hàm thực thi xong sẽ tự động hủy các biến tạm và trả về giá trị mặc định là None.

Code sai:

# output sai là: In ra None
def dem(lst):
    am = 0
    # ... logic đếm ...
    # Chỗ này thiếu lệnh return

Code đúng:

# output đúng là: In ra tuple (số lượng đếm được)
def dem(lst):
    am = 0
    # ... logic đếm ...
    return am # Trả dữ liệu ra ngoài

Câu hỏi thường gặp 

Đếm số nguyên trong list Python là gì?

Đếm số nguyên trong Python là quá trình bạn dùng vòng lặp duyệt qua các phần tử của cấu trúc dữ liệu mảng (list), kiểm tra xem phần tử đó có thuộc kiểu int hay không, và sau đó phân loại đếm xem nó thuộc nhóm lớn hơn 0, nhỏ hơn 0 hay bằng 0.

Tại sao phải dùng isinstance thay vì type() khi kiểm tra kiểu?

Trong các dự án Python thực tế, isinstance() thường được ưu tiên hơn type() vì nó hỗ trợ nhận diện tính đa hình (kế thừa lớp). Tuy nhiên, riêng trong bài toán bắt buộc loại trừ kiểu bool như đếm số nguyên thuần túy này, kết hợp type() is int lại mang tính chặt chẽ và an toàn hơn.

Làm thế nào để đếm số nguyên dương Python bằng hàm built-in nhanh nhất?

Nếu bạn chắc chắn 100% list đầu vào chỉ toàn là con số hợp lệ, bạn có thể viết một dòng code rút gọn bằng List Comprehension: sum(1 for x in lst if x > 0). Tuy nhiên, cách này bắt buộc phải lặp lại nhiều lần nếu muốn đếm cả số âm và số không, gây giảm hiệu năng.

Cách hàm đếm số nguyên âm Python hoạt động với bộ nhớ như thế nào?

Thuật toán duyệt mảng 1 lần (1-pass) như trong bài viết hoạt động với độ phức tạp không gian là O(1). Nghĩa là dù list của bạn có 10 phần tử hay 1 triệu phần tử, bộ nhớ RAM tiêu tốn cho việc duy trì 3 biến đếm (hoặc 1 dictionary nhỏ) là hoàn toàn tĩnh và không hề phình to ra.

Nên dùng 3 biến đếm hay dùng cấu trúc Dictionary để phân loại biến đếm?

Nếu bạn đang làm bài tập kiểm tra 15 phút trên lớp hoặc luyện thi thuật toán cơ bản, hãy dùng 3 biến đếm để dễ rà soát lỗi nhanh. Hãy dùng Dictionary khi bạn viết một module backend cần trả dữ liệu định dạng JSON cho một nhóm khác lập trình hiển thị giao diện Frontend.

Sự khác biệt khi code đếm số nguyên âm dương Python có chứa số thực (float)?

Nếu đề bài mở rộng yêu cầu đếm cả số thực (float) thay vì chỉ số nguyên (int), bạn chỉ cần thay đổi màng lọc kiểm tra kiểu ở bước đầu tiên. Thay vì type(x) is int, bạn dùng isinstance(x, (int, float)) để cho phép các số thập phân như 3.14 lọt vào rẽ nhánh kiểm tra lớn nhỏ.

Tại sao code đếm biến thể từ khóa đếm số không trong list lại bị TypeError?

Lỗi TypeError chắc chắn phát sinh khi vòng lặp của bạn chạm trán một dữ liệu kiểu chuỗi (string) và cố gắng so sánh if 'a' == 0. Lỗi này là hồi chuông cảnh báo mã nguồn của bạn đang thiếu bước “làm sạch dữ liệu” — kiểm tra biến đó có phải là số hay không trước khi làm toán.


Kết luận

Với bài toán đếm số nguyên trong danh sách, việc viết đúng cấu trúc if-elif-else chỉ mới giải quyết được 50% yêu cầu thực tế. 50% còn lại nằm ở bản lĩnh kiểm soát dữ liệu ngoại lệ, đảm bảo chương trình không bị văng lỗi khi nhận input “rác”. Hãy dùng Cách 1 (3 biến) khi bạn mới bắt đầu để rèn luyện tư duy luồng chạy, và chuyển sang Cách 2 (Dictionary) khi bạn muốn xây dựng các hàm chuẩn mực cho dự án lớn.

Bạn đã giải theo Cách 1 hay Cách 2? Hay có hướng xử lý tối ưu code ngắn hơn bằng filter/map? Chia sẻ ở phần bình luận — đôi khi người học tìm ra những cách xử lý thông minh hơn cả giáo trình gốc.

Các khóa học liên quan: 

Một số sản phẩm từ Python:

Một số sách lập trình Python bạn hãy tham khảo

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *