Làm cách nào để trao đổi khóa với các giá trị trong từ điển?


96

Tôi nhận một từ điển làm đầu vào và muốn trả lại một từ điển có các khóa sẽ là giá trị của đầu vào và giá trị của nó sẽ là các khóa nhập tương ứng. Giá trị là duy nhất.

Ví dụ: giả sử đầu vào của tôi là:

a = dict()
a['one']=1
a['two']=2

Tôi muốn đầu ra của mình là:

{1: 'one', 2: 'two'}

Để làm rõ, tôi muốn kết quả của tôi tương đương với kết quả sau:

res = dict()
res[1] = 'one'
res[2] = 'two'

Có cách nào để đạt được điều này không?


1
Xem stackoverflow.com/questions/1087694/... cho một câu hỏi giống hệt nhau mà có một câu trả lời tốt đẹp nếu bạn đang sử dụng Python 3
Stephen Edmonds

@Stephen: xem câu trả lời được bình chọn nhiều thứ hai, nó giống với câu được chấp nhận trong câu hỏi mà bạn đã liên kết. Đám đông khán giả ưa thích câu trả lời khác mặc dù ...
Roee Adler

4
Python không phải là perl, python không phải là ruby. Số lượng khả năng đọc. Thưa thớt tốt hơn dày đặc. Với điều này, tất cả các phương pháp của những câu trả lời này chỉ là dở; một trong những câu hỏi là cách tốt nhất để đi.
o0 '.

3
bản sao có thể xảy ra đối với ánh xạ ngược / nghịch đảo Python
Cory

Câu trả lời:


147

Python 2:

res = dict((v,k) for k,v in a.iteritems())

Python 3 (nhờ @erik):

res = dict((v,k) for k,v in a.items())

14
Mặc dù điều này có vẻ đúng, nhưng thực sự tốt nếu thêm một lời giải thích về cách hoạt động của nó thay vì chỉ mã.
Sẽ

4
Điều gì xảy ra nếu các giá trị không phải là duy nhất? Khi đó, các khóa phải là một danh sách ... ví dụ: d = {'a': 3, 'b': 2, 'c': 2} {v: k for k, v in d.iteritems ()} { 2: 'b', 3: 'a'} phải là {2: ['b', 'c'], 3: 'a'}
Hanan Shteingart

4
@HananShteingart: câu hỏi của OP các giá trị đã nêu là duy nhất. Vui lòng tạo một bài đăng câu hỏi riêng cho trường hợp của bạn (và tốt hơn là liên kết nó ở đây cho những người khác).
liori

mã python2 hoạt động ... nhưng khả năng hiểu danh sách thiếu dấu []. không hiểu danh sách không yêu cầu []?
Trevor Boyd Smith

@TrevorBoydSmith: đây không phải là hiểu danh sách, đây là một biểu thức trình tạo .
liori

55
new_dict = dict(zip(my_dict.values(), my_dict.keys()))

4
Các giá trị () và khóa () có thực sự được đảm bảo có cùng thứ tự không?
Lennart Regebro

1
vâng, từ python.org/dev/peps/pep-3106 Đặc tả ngụ ý rằng thứ tự các mục được trả về bởi .keys (), .values ​​() và .items () là giống nhau (giống như trong Python 2.x), bởi vì tất cả thứ tự đều bắt nguồn từ trình lặp dict (có thể là tùy ý nhưng ổn định miễn là một dict không được sửa đổi). nhưng câu trả lời này cần gọi my_dict hai lần (một cho giá trị, một cho khóa). có lẽ điều này không lý tưởng.
sunqiang

4
Có, câu trả lời này lặp lại qua bài đọc hai lần. Câu trả lời của sunqiang thích hợp hơn cho một từ điển lớn vì nó chỉ yêu cầu một lần lặp lại.
Carl Meyer,

@Carl Meyer: đồng ý, ngoài ra, anh ấy đang sử dụng itertools tốt hơn rất nhiều cho các bộ dữ liệu lớn. mặc dù tôi tự hỏi liệu lệnh gọi dict () cuối cùng cũng đang phát trực tuyến hay nó lần đầu tiên tập hợp toàn bộ danh sách các cặp
Javier

@CarlMeyer bổ sung cho n> 1e6 (hoặc 1e9), việc sử dụng bộ nhớ cũng sẽ thực sự lớn ... và cũng làm chậm điều này rất nhiều.
Trevor Boyd Smith

47

Từ Python 2.7 trở đi, bao gồm cả 3.0+, có một phiên bản ngắn hơn, dễ đọc hơn:

>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}

30
In [1]: my_dict = {'x':1, 'y':2, 'z':3}

In [2]: dict((value, key) for key, value in my_dict.iteritems())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}

3
Không có trong câu hỏi ban đầu, tôi chỉ tò mò điều gì sẽ xảy ra nếu bạn có các giá trị trùng lặp trong từ điển gốc và sau đó hoán đổi khóa / giá trị bằng phương pháp này?
Andre Miller

2
@Andre Miller: Phải mất sự xuất hiện cuối cùng của khóa cụ thể: dict (((1,3), (1,2))) == {1: 2}
balpha

2
các bản sao sẽ bị ghi đè bằng bản dupe gặp phải lần cuối.
Christopher

2
@Andre Miller: Và bởi vì d.items () trả về các mục theo thứ tự tùy ý nên bạn nhận được một khóa tùy ý cho các giá trị trùng lặp.
Ants Aasma

Tôi nghĩ rằng nó sẽ lấy cặp giá trị, khóa cuối cùng mà nó tìm thấy. Nó giống như một ['x'] = 3. Sau đó, bạn đặt ['x'] = 4.
riza

28

Bạn có thể tận dụng comprehensions dict :

res = {v: k for k, v in a.iteritems()}

Đã chỉnh sửa: Đối với Python 3, sử dụng a.items()thay vì a.iteritems(). Các cuộc thảo luận về sự khác biệt giữa chúng có thể được tìm thấy trong các iteritem bằng Python trên SO.


18

Bạn có thể thử:

d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.iteritems())
d2
  {'two': 2, 'one': 1}

Lưu ý rằng bạn không thể 'đảo ngược' từ điển nếu

  1. Nhiều khóa có cùng giá trị. Ví dụ {'one':1,'two':1}. Từ điển mới chỉ có thể có một mục có khóa 1.
  2. Một hoặc nhiều giá trị không thể truy cập được. Ví dụ {'one':[1]}. [1]là một giá trị hợp lệ nhưng không phải là một khóa hợp lệ.

Xem chủ đề này trên danh sách gửi thư python để thảo luận về chủ đề này.


Cũng +1 về lưu ý về việc đảm bảo các giá trị trong chính tả ban đầu là duy nhất; nếu không, bạn sẽ bị ghi đè trong lệnh 'đảo ngược' ... và điều này (tôi vừa tìm thấy điều này với chi phí của tôi) có thể gây ra các lỗi phức tạp trong mã của bạn!
monojohnny

15

Câu trả lời hàng đầu hiện tại giả định các giá trị là duy nhất, điều này không phải lúc nào cũng đúng. Điều gì xảy ra nếu các giá trị không phải là duy nhất? Bạn sẽ mất thông tin! Ví dụ:

d = {'a':3, 'b': 2, 'c': 2} 
{v:k for k,v in d.iteritems()} 

lợi nhuận {2: 'b', 3: 'a'}.

Thông tin về 'c'đã hoàn toàn bị bỏ qua. Lý tưởng nhất là nó phải là một cái gì đó như thế nào {2: ['b','c'], 3: ['a']}. Đây là những gì triển khai dưới cùng làm.

Python 2.x

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.iteritems():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv

Python 3.x

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.items():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv

đây phải là câu trả lời chính xác vì nó bao gồm một trường hợp tổng quát hơn
Leon Rai

Cảm ơn vì điều này! Tôi đã mất thông tin với các giải pháp khác.
Cam

14

res = dict(zip(a.values(), a.keys()))


4
dict không đảm bảo rằng các giá trị () và các khóa () của nó sẽ trả về các phần tử theo cùng một thứ tự. Ngoài ra, các khóa (), giá trị () và zip () trả về một danh sách, trong đó một trình lặp là đủ.
liori

19
@liori: Bạn nhầm rồi. dict đảm bảo rằng các giá trị () và khóa () của nó SẼ theo cùng một thứ tự, nếu bạn không sửa đổi dict giữa các lần gọi giá trị () và khóa () tất nhiên. Tài liệu nói rằng tại đây: (đọc phần "Lưu ý": docs.python.org/library/stdtypes.html#dict.items ) "Nếu các mục (), khóa (), giá trị (), iteritems (), iterkeys ( ) và itervalues ​​() được gọi mà không có sửa đổi can thiệp vào từ điển, danh sách sẽ trực tiếp tương ứng. "
nosklo

1
Được rồi, tôi nhầm rồi ... Tôi chưa kiểm tra tài liệu trực tuyến. Cảm ơn bạn đã chỉ điều này.
liori

Bạn có thể sử dụng trình lặp itertools.izip thay vì zip để làm cho câu trả lời này hiệu quả hơn.
Alasdair

Và iterkeys và itervalues. Nhưng cũng giống như cũng có thể sử dụng iteritems ()
nosklo

14
new_dict = dict( (my_dict[k], k) for k in my_dict)

hoặc thậm chí tốt hơn, nhưng chỉ hoạt động trong Python 3:

new_dict = { my_dict[k]: k for k in my_dict}

2
Trên thực tế, hiểu chính xác ( PEP 274 ) cũng hoạt động với Python 2.7.
Arseny

10

Một cách khác để mở rộng phản hồi của Ilya Prokin là thực sự sử dụng reversedhàm.

dict(map(reversed, my_dict.items()))

Về bản chất, từ điển của bạn được lặp lại thông qua (sử dụng .items()) trong đó mỗi mục là một cặp khóa / giá trị và các mục đó được hoán đổi bằng reversedhàm. Khi điều này được chuyển cho hàm dicttạo, nó sẽ biến chúng thành các cặp khóa / giá trị mà bạn muốn.


6

Đề xuất để cải thiện câu trả lời của Javier:

dict(zip(d.values(),d))

Thay vì d.keys()bạn có thể viếtd , bởi vì nếu bạn duyệt qua từ điển bằng trình lặp, nó sẽ trả về các khóa của từ điển liên quan.

Ví dụ. cho hành vi này:

d = {'a':1,'b':2}
for k in d:
 k
'a'
'b'


2
dict(map(lambda x: x[::-1], YourDict.items()))

.items()trả về một danh sách các bộ giá trị (key, value). map()đi qua các phần tử của danh sách và áp dụng lambda x:[::-1]cho từng phần tử của nó (tuple) để đảo ngược nó, vì vậy mỗi tuple sẽ (value, key)nằm trong danh sách mới được đưa ra khỏi bản đồ. Cuối cùng, dict()tạo một chính tả từ danh sách mới.


.items () trả về một danh sách các bộ giá trị (khóa, giá trị). map () đi qua các phần tử của danh sách và áp dụng lambda x:[::-1]cho từng phần tử của nó (tuple) để đảo ngược nó, do đó mỗi tuple trở thành (giá trị, khóa) trong danh sách mới được đưa ra khỏi bản đồ. Cuối cùng, dict () tạo một dict từ danh sách mới.
Ilya Prokin

1

Sử dụng vòng lặp : -

newdict = {} #Will contain reversed key:value pairs.

for key, value in zip(my_dict.keys(), my_dict.values()):
    # Operations on key/value can also be performed.
    newdict[value] = key

1

Nếu bạn đang sử dụng Python3, nó hơi khác một chút:

res = dict((v,k) for k,v in a.items())

1

Thêm giải pháp tại chỗ:

>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> for k in list(d.keys()):
...     d[d.pop(k)] = k
... 
>>> d
{'two': 2, 'one': 1, 'four': 4, 'three': 3}

Trong Python3, điều quan trọng là bạn phải sử dụng list(d.keys())dict.keystrả về chế độ xem các khóa. Nếu bạn đang sử dụng Python2, d.keys()là đủ.


1

Câu trả lời của Hanan là câu trả lời đúng vì nó bao gồm nhiều trường hợp chung hơn (các câu trả lời khác khá dễ gây hiểu lầm cho những người không biết về tình huống trùng lặp). Một cải tiến cho câu trả lời của Hanan là sử dụng setdefault:

mydict = {1:a, 2:a, 3:b}   
result = {}
for i in mydict:  
   result.setdefault(mydict[i],[]).append(i)
print(result)
>>> result = {a:[1,2], b:[3]}
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.