Sử dụng ký hiệu hiểu danh sách Python

Kinh doanh

Trong Python, thật đơn giản để sử dụng ký hiệu hiểu danh sách khi tạo một danh sách mới.(List comprehensions)

Trong bài viết này, trước tiên chúng ta sẽ thảo luận về những điều sau

  • Loại ký hiệu hiểu danh sách cơ bản
  • Liệt kê ký hiệu hiểu với phân nhánh có điều kiện bằng if
  • Kết hợp với các toán tử bậc ba (nếu xử lý giống như phương thức khác)
  • zip(),enumerate()Sự kết hợp với những
  • ký hiệu bao gồm danh sách lồng nhau

Tiếp theo, chúng tôi sẽ giải thích tập hợp các ký hiệu hiểu danh sách với mã mẫu.

  • đặt ký hiệu bao gồm(Set comprehensions)
  • ký hiệu bao gồm từ điển(Dict comprehensions)
  • loại máy phát điện(Generator expressions)

Loại ký hiệu hiểu danh sách cơ bản

Ký hiệu hiểu danh sách được viết như sau.

[Expression for Any Variable Name in Iterable Object]

Nó lấy mỗi phần tử của một đối tượng có thể lặp lại, chẳng hạn như danh sách, bộ hoặc dải ô bằng một tên biến tùy ý và đánh giá nó bằng một biểu thức. Một danh sách mới với kết quả đánh giá là một phần tử được trả về.

Một ví dụ được đưa ra cùng với câu lệnh for tương đương.

squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
    squares.append(i**2)

print(squares)
# [0, 1, 4, 9, 16]

Quá trình tương tự có thể được thực hiện với map (), nhưng ký hiệu hiểu danh sách được ưu tiên hơn vì tính đơn giản và rõ ràng của nó.

Liệt kê ký hiệu hiểu với phân nhánh có điều kiện bằng if

Phân nhánh có điều kiện với if cũng có thể. Viết if trong hậu tố như sau.

[Expression for Any Variable Name in Iterable Object if Conditional Expression]

Chỉ các phần tử của đối tượng có thể lặp có biểu thức điều kiện là true mới được đánh giá bằng biểu thức và một danh sách mới có các phần tử là kết quả được trả về.

Bạn có thể sử dụng bất kỳ tên biến nào trong biểu thức điều kiện.

Một ví dụ được đưa ra cùng với câu lệnh for tương đương.

odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
    if i % 2 == 1:
        odds.append(i)

print(odds)
# [1, 3, 5, 7, 9]

Quá trình tương tự có thể được thực hiện với filter (), nhưng ký hiệu hiểu danh sách được ưu tiên hơn vì tính đơn giản và rõ ràng của nó.

Kết hợp với các toán tử bậc ba (nếu xử lý giống như phương thức khác)

Trong ví dụ trên, chỉ những phần tử đáp ứng tiêu chí mới được xử lý và những phần tử không đáp ứng tiêu chí bị loại khỏi danh sách mới.

Nếu bạn muốn chuyển đổi quá trình tùy thuộc vào điều kiện hoặc nếu bạn muốn xử lý các phần tử không thỏa mãn điều kiện theo cách khác, như trong trường hợp khác, hãy sử dụng toán tử bậc ba.

Trong Python, toán tử bậc ba có thể được viết như sau

Value When True if Conditional Expression else Value When False

Điều này được sử dụng trong phần diễn đạt của ký hiệu đọc hiểu danh sách như được hiển thị bên dưới.

[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]

Một ví dụ được đưa ra cùng với câu lệnh for tương đương.

odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
    if i % 2 == 1:
        odd_even.append('odd')
    else:
        odd_even.append('even')

print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

Cũng có thể viết biểu thức sử dụng tên biến tùy ý cho các giá trị true và false.

Nếu điều kiện được thỏa mãn, một số xử lý sẽ được thực hiện, nếu không giá trị của đối tượng có thể lặp lại ban đầu được giữ nguyên.

odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]

Kết hợp với zip () và enumerate ()

Các hàm hữu ích thường được sử dụng trong câu lệnh for bao gồm zip (), kết hợp nhiều tệp lặp và enumerate (), trả về một giá trị cùng với chỉ mục của nó.

Tất nhiên, có thể sử dụng zip () và enumerate () với ký hiệu hiểu danh sách. Nó không phải là một cú pháp đặc biệt và không khó nếu bạn xem xét sự tương ứng với câu lệnh for.

Ví dụ về zip ().

l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']

l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
    l_zip.append((s1, s2))

print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]

Ví dụ về enumerate ().

l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
    l_enu.append((i, s))

print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]

Ý tưởng cũng giống như trước đây khi sử dụng if.

l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]

Mỗi phần tử cũng có thể được sử dụng để tính toán một phần tử mới.

l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]

l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]

ký hiệu bao gồm danh sách lồng nhau

Giống như lồng cho các vòng lặp, ký hiệu hiểu danh sách cũng có thể được lồng vào nhau.

[Expression for Variable Name 1 in Iterable Object 1
    for Variable Name 2 in Iterable Object 2
        for Variable Name 3 in Iterable Object 3 ... ]

Để thuận tiện, ngắt dòng và thụt lề đã được thêm vào, nhưng không bắt buộc đối với ngữ pháp; chúng có thể được tiếp tục trên một dòng.

Một ví dụ được đưa ra cùng với câu lệnh for tương đương.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
    for x in row:
        flat.append(x)

print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Cũng có thể sử dụng nhiều biến.

cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

Bạn cũng có thể thực hiện phân nhánh có điều kiện.

cells = [(row, col) for row in range(3)
         for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]

Cũng có thể phân nhánh có điều kiện cho mỗi đối tượng có thể lặp lại.

cells = [(row, col) for row in range(3) if row % 2 == 0
         for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]

đặt ký hiệu bao gồm(Set comprehensions)

Việc thay đổi dấu ngoặc vuông [] trong ký hiệu hiểu danh sách thành dấu ngoặc nhọn {} sẽ tạo ra một tập hợp (đối tượng kiểu tập hợp).

{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}

print(s)
# {0, 1, 4, 9, 16}

ký hiệu bao gồm từ điển(Dict comprehensions)

Các từ điển (đối tượng kiểu dict) cũng có thể được tạo với ký hiệu đọc hiểu.

{} và chỉ định khóa và giá trị trong phần biểu thức dưới dạng key: value.

{Key: Value for Any Variable Name in Iterable Object}

Bất kỳ biểu thức nào cũng có thể được chỉ định cho khóa và giá trị.

l = ['Alice', 'Bob', 'Charlie']

d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}

Để tạo một từ điển mới từ danh sách các khóa và giá trị, hãy sử dụng hàm zip ().

keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]

d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}

loại máy phát điện(Generator expressions)

Nếu dấu ngoặc vuông [] trong ký hiệu nhận dạng danh sách được sử dụng làm dấu ngoặc tròn (), thì một trình tạo được trả về thay vì một tuple. Đây được gọi là biểu thức máy phát điện.

Ví dụ về ký hiệu hiểu danh sách.

l = [i**2 for i in range(5)]

print(l)
# [0, 1, 4, 9, 16]

print(type(l))
# <class 'list'>

Ví dụ về biểu thức máy phát điện. Nếu bạn in () trình tạo như hiện tại, nó sẽ không in ra nội dung của nó, nhưng nếu bạn chạy nó với câu lệnh for, bạn có thể lấy nội dung.

g = (i**2 for i in range(5))

print(g)
# <generator object <genexpr> at 0x10af944f8>

print(type(g))
# <class 'generator'>

for i in g:
    print(i)
# 0
# 1
# 4
# 9
# 16

Biểu thức trình tạo cũng cho phép phân nhánh có điều kiện và lồng vào nhau bằng cách sử dụng if cũng như ký hiệu hiểu danh sách.

g_cells = ((row, col) for row in range(0, 3)
           for col in range(0, 2) if col == row)

print(type(g_cells))
# <class 'generator'>

for i in g_cells:
    print(i)
# (0, 0)
# (1, 1)

Ví dụ: nếu một danh sách có nhiều phần tử được tạo bằng cách sử dụng ký hiệu hiểu danh sách và sau đó lặp lại bằng câu lệnh for, thì danh sách chứa tất cả các phần tử sẽ được tạo ở đầu nếu ký hiệu hiểu danh sách được sử dụng. Mặt khác, nếu bạn sử dụng biểu thức trình tạo, mỗi lần lặp lại vòng lặp, các phần tử được tạo ra từng phần tử một, do đó sẽ giảm dung lượng bộ nhớ được sử dụng.

Nếu biểu thức trình tạo là đối số duy nhất của hàm, thì có thể bỏ qua dấu ngoặc tròn ().

print(sum([i**2 for i in range(5)]))
# 30

print(sum((i**2 for i in range(5))))
# 30

print(sum(i**2 for i in range(5)))
# 30

Đối với tốc độ xử lý, ký hiệu hiểu danh sách thường nhanh hơn ký hiệu trình tạo khi tất cả các phần tử được xử lý.

Tuy nhiên, khi đánh giá với tất cả () hoặc bất kỳ (), ví dụ, kết quả được xác định khi có sai hoặc đúng, vì vậy sử dụng biểu thức trình tạo có thể nhanh hơn sử dụng ký hiệu hiểu danh sách.

Không có ký hiệu tuple hiểu, nhưng nếu bạn sử dụng biểu thức trình tạo làm đối số của tuple (), bạn có thể tạo một tuple trong ký hiệu hiểu.

t = tuple(i**2 for i in range(5))

print(t)
# (0, 1, 4, 9, 16)

print(type(t))
# <class 'tuple'>