Hiểu từ điển Python


386

Có thể tạo một sự hiểu từ điển trong Python (cho các phím) không?

Nếu không có danh sách hiểu, bạn có thể sử dụng một cái gì đó như thế này:

l = []
for n in range(1, 11):
    l.append(n)

Chúng ta có thể rút ngắn điều này thành một sự hiểu biết danh sách : l = [n for n in range(1, 11)].

Tuy nhiên, giả sử tôi muốn đặt các khóa của từ điển có cùng giá trị. Tôi có thể làm:

d = {}
for n in range(1, 11):
     d[n] = True # same value for each

Tôi đã thử điều này:

d = {}
d[i for i in range(1, 11)] = True

Tuy nhiên, tôi nhận được một SyntaxErrortrên for.

Ngoài ra (tôi không cần phần này, nhưng chỉ cần tự hỏi), bạn có thể đặt các khóa của từ điển thành một loạt các giá trị khác nhau không, như sau:

d = {}
for n in range(1, 11):
    d[n] = n

Điều này có thể với một sự hiểu biết từ điển?

d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]

Điều này cũng đặt ra một SyntaxErrortrên for.


3
Để biết thông tin của độc giả trong tương lai: Mảng NumPy cho phép bạn đặt nhiều yếu tố thành một giá trị hoặc danh sách các giá trị, theo cách bạn đang cố gắng thực hiện. Mặc dù nếu bạn chưa có lý do để sử dụng NumPy, có lẽ nó không xứng đáng với tính năng này.
David Z

Câu trả lời:


520

Có những cách hiểu từ điển trong Python 2.7+ , nhưng chúng không hoạt động hoàn toàn theo cách bạn đang cố gắng. Giống như một sự hiểu biết danh sách, họ tạo ra một từ điển mới ; bạn không thể sử dụng chúng để thêm khóa vào một từ điển hiện có. Ngoài ra, bạn phải chỉ định các khóa và giá trị, mặc dù tất nhiên bạn có thể chỉ định giá trị giả nếu bạn muốn.

>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Nếu bạn muốn đặt tất cả chúng thành True:

>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}

Những gì bạn dường như đang yêu cầu là một cách để đặt nhiều khóa cùng một lúc trên một từ điển hiện có. Không có lối tắt trực tiếp cho điều đó. Bạn có thể lặp như bạn đã trình bày hoặc bạn có thể sử dụng khả năng hiểu từ điển để tạo ra một lệnh mới với các giá trị mới và sau đó thực hiện oldDict.update(newDict)để hợp nhất các giá trị mới vào chính tả cũ.


15
FWIW, dict.updatecũng có thể chấp nhận một cặp giá trị khóa lặp giống như hàm dicttạo
mgilson

6
Lưu ý rằng nếu bạn tạo một từ điển với tất cả các giá trị như nhau, hãy sử dụng dict.fromkeys(). Vì vậy, để thiết lập tất cả các giá trị True, sử dụng dict.fromkeys(range(5), True). Xem ra, giá trị không được sao chép , vì vậy bạn có thể muốn tránh điều này khi bạn có một giá trị có thể thay đổi; nó sẽ được chia sẻ giữa tất cả các khóa.
Martijn Pieters

2
Lưu ý: các khóa cũng có thể là kết quả của một phương thức : { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Cả hai có thể được thực hiện trong cùng một biểu thức : { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
Zaaier

151

Bạn có thể sử dụng dict.fromkeysphương thức lớp ...

>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}

Đây là cách nhanh nhất để tạo một từ điển trong đó tất cả các khóa ánh xạ tới cùng một giá trị.

Nhưng làm không sử dụng này với các đối tượng có thể thay đổi :

d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!

Nếu bạn không thực sự cần phải khởi tạo tất cả các khóa, thì cũng defaultdictcó thể hữu ích:

from collections import defaultdict
d = defaultdict(True)

Để trả lời phần thứ hai, một cách hiểu chính tả là thứ bạn cần:

{k: k for k in range(10)}

Bạn có thể không nên làm điều này nhưng bạn cũng có thể tạo một lớp con dicthoạt động giống như defaultdictnếu bạn ghi đè __missing__:

>>> class KeyDict(dict):
...    def __missing__(self, key):
...       #self[key] = key  # Maybe add this also?
...       return key
... 
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}

Lưu ý rằng trong trường hợp d = defaultdict(lambda: True), lambda không bắt buộc vì True là (hoặc không nên) có thể thay đổi.
rhbvkleef

28
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}

22

Tôi thực sự thích nhận xét @mgilson, vì nếu bạn có hai lần lặp, một lần lượt tương ứng với các khóa và các giá trị khác, bạn cũng có thể thực hiện như sau.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))

cho

d = {'a': 1, 'b': 2, 'c': 3}


4
Sử dụng Hiểu Dict:{i:j for i in keys for j in values}
LoMaPh

11

Sử dụng dict () trên danh sách các bộ dữ liệu, giải pháp này sẽ cho phép bạn có các giá trị tùy ý trong mỗi danh sách, miễn là chúng có cùng độ dài

i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])

12
Một ghi chú bên lề, đây là điều tương tự nhưd = dict(zip(i_s,x_s))
mgilson

10

Xem xét ví dụ này về việc đếm sự xuất hiện của các từ trong danh sách bằng cách hiểu từ điển

my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)

Và kết quả là

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}

Điều này thật thú vị, mặc dù không hiệu quả nhất vì bạn sẽ đếm các phím như 'xin chào' nhiều lần
FuriousGeorge

7

Mục đích chính của việc hiểu danh sách là tạo ra một danh sách mới dựa trên danh sách khác mà không thay đổi hoặc phá hủy danh sách ban đầu.

Thay vì viết

    l = []
    for n in range(1, 11):
        l.append(n)

hoặc là

    l = [n for n in range(1, 11)]

bạn chỉ nên viết

    l = range(1, 11)

Trong hai khối mã hàng đầu bạn đang tạo một danh sách mới, lặp qua nó và chỉ trả về từng phần tử. Đó chỉ là một cách đắt tiền để tạo một bản sao danh sách.

Để có được một từ điển mới với tất cả các khóa được đặt thành cùng một giá trị dựa trên một lệnh khác, hãy làm điều này:

    old_dict = {'a': 1, 'c': 3, 'b': 2}
    new_dict = { key:'your value here' for key in old_dict.keys()}

Bạn đang nhận được một SyntaxError vì khi bạn viết

    d = {}
    d[i for i in range(1, 11)] = True

về cơ bản bạn đang nói: "Đặt khóa của tôi 'i cho i trong phạm vi (1, 11)' thành Đúng" và "i cho i trong phạm vi (1, 11)" không phải là khóa hợp lệ, đó chỉ là lỗi cú pháp. Nếu danh sách được hỗ trợ danh sách dưới dạng khóa, bạn sẽ làm một cái gì đó như

    d[[i for i in range(1, 11)]] = True

và không

    d[i for i in range(1, 11)] = True

nhưng danh sách không thể băm được, vì vậy bạn không thể sử dụng chúng làm khóa chính tả.


-3

bạn không thể băm một danh sách như thế. thay vào đó, hãy thử sử dụng bộ dữ liệu

d[tuple([i for i in range(1,11)])] = True
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.