Chuyển đến nội dung chính

Python filter(): Giữ lại những gì bạn cần

Tìm hiểu cách dùng hàm filter() của Python để trích xuất các mục từ list hoặc các iterable khác. Hiểu rõ khác biệt chính giữa filter và các công cụ tương tự trong Python.
· 7 phút đọc

Khám phá cùng AI

Lọc dữ liệu là một trong những tác vụ phổ biến nhất trong Python, và đó là lý do Python giúp bạn làm điều này rất dễ. Một trong những cách đơn giản nhất để lọc dữ liệu là dùng hàm dựng sẵn filter(). Đúng như tên gọi, filter() cho phép bạn lấy ra chỉ những mục đáp ứng một (hoặc nhiều) điều kiện nhất định.

Hướng dẫn này sẽ đưa bạn qua cách thức hoạt động, khi nào nên dùng, và so sánh với các công cụ lọc khác. Mời bạn đọc tiếp!

filter() trong Python làm gì

filter() cho phép bạn lấy ra các phần tử từ list, tuple, hoặc bất kỳ iterable nào, nhưng chỉ khi chúng vượt qua bài kiểm tra của bạn. Bạn cung cấp một hàm (đôi khi còn được gọi là predicate) nhận từng mục và trả về True hoặc False. Nếu kiểm tra vượt qua (tức là hàm của bạn trả về True) filter() sẽ giữ lại. Nếu không, nó sẽ bỏ qua mục đó. Điều này khá dễ hiểu, nên hãy tiếp tục.

Cú pháp Python filter()

Định dạng như sau:

filter(function, iterable)
  • function: Xác định phép kiểm tra bạn muốn áp dụng cho từng mục. Hàm này nên nhận một đối số và trả về True hoặc False.

  • iterable: Cung cấp một list, tuple, string, hoặc bất kỳ đối tượng nào bạn có thể lặp qua.

Khi bạn gọi filter(), nó trả về một đối tượng filter đặc biệt, chứ không phải list hay tuple trực tiếp. Để thực sự làm việc với kết quả đã lọc, bạn thường sẽ bọc đầu ra trong một list hoặc tuple. Thiết kế này giúp filter() hiệu quả, nhưng bạn cần ghi nhớ điều này khi viết mã.

Ví dụ về Python filter()

Hãy thực hành một chút.

Python filter() với hàm tùy chỉnh

Hãy dùng filter() với một hàm do chính chúng ta viết.

Giả sử bạn chỉ muốn giữ các số chẵn từ một list:

def is_even(num):
    return num % 2 == 0

numbers = [1, 2, 3, 4, 5, 6]
result = filter(is_even, numbers)
print(list(result))

Điều này sẽ in ra:

[2, 4, 6]

Lưu ý cách is_even kiểm tra một số có chia hết cho 2 không. filter() dùng hàm tùy chỉnh của chúng ta để kiểm tra từng mục và giữ lại những mục vượt qua kiểm tra.

Python filter() với hàm lambda

Tất nhiên, không phải bộ lọc nào cũng cần một định nghĩa hàm đầy đủ. Đôi khi, quy tắc lọc của bạn đơn giản hoặc chỉ dùng tại một chỗ đến mức đặt tên hàm là không đáng công.

Đây là ví dụ số chẵn tương tự, nhưng dùng lambda để có một phép kiểm tra gọn gàng, ngay tại chỗ:

numbers = [1, 2, 3, 4, 5, 6] 
result = filter(lambda x: x % 2 == 0, numbers) 
print(list(result))

Bạn sẽ nhận được đầu ra y như trước.

Dùng lambda với filter() đặc biệt phổ biến khi bạn muốn giữ mã ngắn gọn và tập trung. Đây là lựa chọn tuyệt vời cho các tác vụ lọc dùng một lần, cho phép bạn diễn đạt quy tắc ngay tại nơi cần dùng.

Python filter() với None làm hàm

Đôi khi, bạn muốn filter() loại bỏ các giá trị rỗng hoặc sai. Những thứ như 0, chuỗi rỗng, None, hoặc False, và chúng ta muốn làm điều này mà không cần viết hàm tùy chỉnh.

Python có một mẹo cho việc này: Nếu bạn đặt đối số hàm trong filter() là None, filter() sẽ tự động loại bỏ mọi mục mà Python coi là False.

Ví dụ như sau:

items = [0, 1, '', 'hello', [], [2, 3], None, False, True] 
result = filter(None, items) 
print(list(result))

Điều này sẽ in ra:

[1, 'hello', [2, 3], True]

Lọc dữ liệu văn bản

Giờ hãy áp dụng filter() cho một vấn đề thực tế hằng ngày. Giả sử bạn có một list từ và chỉ muốn những từ bắt đầu bằng 'a'. Kiểu lọc có mục tiêu như vậy xuất hiện thường xuyên khi xử lý văn bản.

words = ['apple', 'banana', 'apricot', 'cherry', 'avocado'] 
result = filter(lambda word: word.startswith('a'), words) 
print(list(result))

Bạn sẽ nhận được:

['apple', 'apricot', 'avocado']

Lọc với nhiều điều kiện

Đôi khi, tiêu chí lọc của bạn phức tạp hơn. Điều gì xảy ra nếu bạn cần các mục đáp ứng nhiều điều kiện? Dưới đây là cách thực hiện bằng lambda. Trong ví dụ này, chúng ta tìm các số vừa chẵn vừa lớn hơn 10.

numbers = [4, 10, 12, 15, 20, 23, 28] 
result = filter(lambda x: x % 2 == 0 and x > 10, numbers) 
print(list(result))

Kết quả in ra:

[12, 20, 28]

(Nếu có còn nhiều điều kiện hơn nữa, tôi sẽ cân nhắc chuyển từ lambda sang một hàm có tên để rõ ràng hơn.)

filter() so với List Comprehension

List comprehension là một cách phổ biến khác để chọn mục. Cả hai cách đều cho phép bạn lọc dữ liệu, nhưng mỗi cách có phong cách riêng.

Đây là ví dụ số chẵn một lần nữa, lần này dùng list comprehension:

numbers = [1, 2, 3, 4, 5, 6] 
result = [x for x in numbers if x % 2 == 0] 
print(result)
[2, 4, 6]

Cả filter() lẫn list comprehension đều hoàn thành công việc. List comprehension thường dễ đọc hơn cho các bộ lọc đơn giản, đặc biệt khi quy tắc ngắn và rõ.

Mặt khác, filter() hoạt động tốt khi bạn đã làm việc với các hàm, hoặc khi bạn muốn xâu chuỗi nhiều bước xử lý.

Những cách dùng nâng cao hơn

Hãy thử tìm vài trường hợp thú vị hơn:

filter() với các iterable khác

Cũng như với list, filter() còn hoạt động với bất kỳ iterable nào, như tuple, set — thậm chí cả biểu thức generator. Điều này hữu ích vì dữ liệu của bạn không phải lúc nào cũng ở dạng list.

Cách lọc một tuple:

numbers = (10, 15, 20, 25, 30) 
result = filter(lambda x: x > 20, numbers) 
print(tuple(result))

Điều này sẽ in ra:

(25, 30)

Chỉ cần nhớ chuyển đổi đối tượng filter sang kiểu bạn muốn (list, tuple, v.v.) khi cần dùng trực tiếp kết quả.

Tôi cũng đã nhắc đến generator, nên để đầy đủ, tôi sẽ minh họa ví dụ lọc với generator nữa:

numbers = (x for x in range(10))
result = filter(lambda x: x % 2 == 0, numbers)
print(list(result))

Đây là một generator vì dòng này: numbers = (x for x in range(10)) tạo ra một đối tượng generator. (Nó lười thực thi và không tạo tất cả giá trị cùng lúc.)

Dòng cuối: print(list(result)) buộc đánh giá bằng cách chuyển đổi đối tượng filter lười thực thi thành một list.

Kết hợp filter() với map()

Điều gì xảy ra nếu bạn muốn vừa lọc vừa biến đổi dữ liệu, chẳng hạn như trong ví dụ tiếp theo của chúng ta, bình phương chỉ các số chẵn trong một list?

Python giúp việc này trở nên dễ dàng bằng cách cho phép bạn kết hợp filter() và map(). Trước hết, filter() chọn ra các mục bạn muốn, rồi map() áp dụng một hàm khác lên từng mục đó.

Thực hành như sau:

numbers = [1, 2, 3, 4, 5, 6] 
evens = filter(lambda x: x % 2 == 0, numbers) 
squared = map(lambda x: x ** 2, evens) 
print(list(squared))

Điều này in ra:

[4, 16, 36]

Bằng cách xâu chuỗi filter() và map(), bạn có thể xây dựng các pipeline dữ liệu rõ ràng, dễ đọc: trước tiên chọn các mục bạn quan tâm, rồi biến đổi chúng khi cần. Bạn sẽ có nhiều cơ hội dùng mẫu này trong công việc của mình.

Những điều cần lưu ý

Dù filter() hữu ích, vẫn có vài lỗi thường gặp:

  • filter() trả về một đối tượng filter, không phải list. Điều này có thể khiến bạn bối rối nếu mong thấy kết quả ngay. Hãy luôn bọc nó trong list (hoặc tuple) nếu bạn cần xem hoặc tái sử dụng kết quả.

  • filter() chỉ làm việc với một iterable tại một thời điểm. Nếu bạn muốn lọc dựa trên nhiều list, bạn sẽ cần zip chúng lại hoặc dùng cách tiếp cận khác.

  • filter() là lười thực thi (lazy). Nó không thực sự xử lý dữ liệu cho đến khi bạn chuyển nó thành list, tuple, hoặc lặp qua. Hãy ghi nhớ hành vi này khi gỡ lỗi.

Kết luận

Như bạn đã thấy, hàm filter() của Python mang đến cách nhanh chóng để làm sạch dữ liệu bằng cách chỉ giữ lại phần quan trọng. filter() hữu ích dù bạn viết một lambda dùng một lần hay truyền vào một hàm có tên.

Nếu bạn còn chưa rõ cách dùng filter(), hoặc nếu bạn thấy phần này đủ đơn giản và muốn học tiếp, chúng tôi có các tài nguyên tuyệt vời để hỗ trợ. Tôi gợi ý skill track Python Programming Fundamentals.

Josef Waples

Tác giả

Josef Waples

Tôi là một cây bút và biên tập viên về khoa học dữ liệu, đã có bài đóng góp cho các nghiên cứu đăng trên tạp chí khoa học. Tôi đặc biệt quan tâm đến đại số tuyến tính, thống kê, R và các chủ đề tương tự. Tôi cũng chơi cờ vua khá thường xuyên! 

Câu hỏi thường gặp về Python Filter

Hàm Python filter() làm gì?

Hàm filter() nhận một hàm và một iterable, rồi trả về một iterable mới chỉ chứa các mục vượt qua bài kiểm tra. Hàm kiểm tra nên trả về True cho các mục bạn muốn giữ và False cho những mục bạn muốn bỏ qua.

Vì sao tôi cần bọc kết quả của filter() trong list() hoặc tuple()?

filter() trả về một đối tượng filter, tức là một iterator. Để xem hoặc tái sử dụng kết quả đã lọc, bạn thường sẽ chuyển nó thành list hoặc tuple bằng list() hoặc tuple(). Bước này là cần thiết để in, gỡ lỗi, hoặc truyền kết quả cho các hàm khác.

Tôi có thể dùng filter() mà không cần viết hàm tùy chỉnh không?

Có. Bạn có thể dùng hàm lambda cho các kiểm tra ngắn, dùng một lần, hoặc truyền None làm đối số hàm để tự động loại bỏ mọi giá trị "falsy" như 0, '', None và False.

filter() so với list comprehension như thế nào?

Cả filter() và list comprehension đều cho phép bạn lọc dữ liệu, nhưng list comprehension thường dễ đọc hơn cho các điều kiện đơn giản. filter() hữu ích khi tái sử dụng logic qua các hàm hoặc xâu chuỗi với các công cụ như map().

Tôi có thể áp dụng nhiều điều kiện với filter() không?

Chắc chắn rồi. Bạn có thể kết hợp nhiều điều kiện bằng các toán tử logic bên trong hàm kiểm tra hoặc lambda. Với logic phức tạp, thường nên dùng một hàm có tên để mã dễ đọc hơn.

Chủ đề