Як я можу обмінятися ключами зі значеннями у словнику?


97

Я отримую словник як вхід і хочу повернути словник, ключі якого будуть значеннями введення, а значення - відповідними ключами введення. Цінності унікальні.

Наприклад, скажімо, моє введення:

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

Я хотів би, щоб мої результати були:

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

Для уточнення я хотів би, щоб мій результат був еквівалентом наступного:

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

Будь-який акуратний пітонічний спосіб цього досягти?


1
Дивіться stackoverflow.com/questions/1087694/… щодо ідентичного запитання, на яке є приємна відповідь, якщо ви використовуєте Python 3
Стівен Едмондс

@Stephen: див. Другу відповідь, за якою найбільш голосували, вона така ж, як і прийняту у запитанні, на яке ви посилаєтесь. Хоча натовп віддав перевагу іншій відповіді ...
Рої Адлер

4
Python не perl, python не ruby. Підрахунок читабельності. Розріджений краще щільного. З огляду на це, усі методи цих відповідей просто погані ™; питання, про яке йдеться, - найкращий шлях.
o0 '.

3
можливий дублікат відображення зворотного / зворотного Python
Кори

Відповіді:


148

Python 2:

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

Python 3 (завдяки @erik):

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

14
Хоча це здається правильним, дійсно добре додати пояснення того, як це працює, а не просто код.
Вийде

4
Що робити, якщо значення не є унікальними? Тоді ключі повинні бути списком ... наприклад: d = {'a': 3, 'b': 2, 'c': 2} {v: k для k, v у d.iteritems ()} { 2: 'b', 3: 'a'} має бути {2: ['b', 'c'], 3: 'a'}
Hanan Shteingart

4
@HananShteingart: значення запитання, викладеного ОП, є унікальними. Будь ласка, створіть окрему публікацію запитань для своєї справи (і бажано зв’яжіть її тут для інших людей).
liori

код python2 працює ... але в розумінні списку відсутнє [і ]. чи для розуміння списку не потрібно [і ]?
Тревор Бойд Сміт,

@TrevorBoydSmith: це не розуміння списку, це вираз генератора .
liori

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

4
Чи справді значення () та ключі () мають однакове впорядкування?
Леннарт Регебро

1
так, з python.org/dev/peps/pep-3106 Специфікація передбачає, що порядок повернення елементів за допомогою .keys (), .values ​​() та .items () однаковий (як і в Python 2.x), оскільки порядок є похідним від ітератора dict (який, мабуть, довільний, але стабільний, доки dict не змінюється). але для цієї відповіді потрібно двічі викликати my_dict (один для значень, один для ключів). можливо це не ідеально.
sunqiang

4
Так, ця відповідь двічі повторюється через дикт. Відповідь sunqiang є кращим для великого словника, оскільки він вимагає лише однієї ітерації.
Carl Meyer

@Carl Meyer: погодьтеся, він також використовує інструменти itertools, які набагато кращі для великих наборів даних. хоча мені цікаво, чи виклик остаточного dict () також транслюється, чи він спочатку збирає цілий список пар
Хав'єр

@CarlMeyer додатково для n> 1e6 (або 1e9) використання пам'яті також буде дуже великим ... і це також сповільнить купу.
Тревор Бойд Сміт

47

Починаючи з Python 2.7, включаючи 3.0+, існує, мабуть, коротша, читабельніша версія:

>>> 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
Не в оригінальному запитанні, мені просто цікаво, що трапиться, якщо у вас будуть повторювані значення в оригінальному словнику, а потім поміняєте ключом / значенням цей метод?
Andre Miller,

2
@Andre Miller: Він приймає останню появу конкретного ключа: dict (((1,3), (1,2))) == {1: 2}
balpha

2
дублікати будуть перезаписані з останньою обманою.
Крістофер

2
@Andre Miller: І оскільки d.items () повертає елементи у довільному порядку, ви отримуєте довільний ключ для повторюваних значень.
Ants Aasma

Я думаю, що для цього потрібен останній ключ, пара значень, який він знайшов. Це як ['x'] = 3. Тоді ви встановлюєте ['x'] = 4.
riza

28

Ви можете скористатися розумінням дикту :

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

Відредаговано: Для Python 3 використовуйте a.items()замість a.iteritems(). Дискусії про відмінності між ними можна знайти в ітераціях у Python на SO.


18

Ви можете спробувати:

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

Пам'ятайте, що ви не можете "змінити" словник, якщо

  1. Більше одного ключа поділяють одне і те ж значення. Наприклад {'one':1,'two':1}. Новий словник може містити лише один пункт із ключем 1.
  2. Одне або кілька значень є незмінними. Наприклад {'one':[1]}. [1]є дійсним значенням, але не дійсним ключем.

Див. Цю тему в списку розсилки python для обговорення цієї теми.


Також +1 про примітку про те, щоб значення в оригінальному дикті були унікальними; інакше ви отримаєте заміни в "зворотному" дикті ... і це (я щойно знайшов це на свою вартість) може спричинити хитрі помилки у вашому коді!
monojohnny

15

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


4
dict не гарантує, що його значення () та ключі () повернуть елементи в однаковому порядку. Крім того, ключі (), значення () та zip () повертають список, де ітератора було б достатньо.
liori

19
@liori: Ти помиляєшся. dict гарантує, що його значення () та ключі () БУДУТЬ в однаковому порядку, якщо, звичайно, ви не зміните дикт між викликами значень () та ключів (). У документації зазначено, що тут: (прочитайте частину "Примітка": docs.python.org/library/stdtypes.html#dict.items ) "Якщо items (), keys (), values ​​(), iteritems (), iterkeys ( ), а значення itervalues ​​() викликаються без втручання в словник, списки будуть безпосередньо відповідати. "
nosklo

1
Добре, тоді я помиляюся ... Я не перевіряв онлайн-документи. Дякуємо, що вказали на це.
liori

Ви можете використовувати ітератор itertools.izip замість zip, щоб зробити цю відповідь більш ефективною.
Alasdair,

І iterkey та itervalues. Але міг так само добре використовувати iteritems ()
nosklo

15

Поточна відповідь передбачає, що значення є унікальними, що не завжди має місце. Що робити, якщо значення не є унікальними? Ви втратите інформацію! Наприклад:

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

повертається {2: 'b', 3: 'a'}.

Інформація про 'c'була повністю проігнорована. В ідеалі це мало бути щось на зразок {2: ['b','c'], 3: ['a']}. Це те, що робить нижня реалізація.

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

це повинна бути правильна відповідь, оскільки вона охоплює більш загальний випадок
Леон Рай

Дякую за це! Я втрачав інформацію з іншими рішеннями.
Cam

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

або навіть краще, але працює лише в Python 3:

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

2
Насправді Dict Comprehension ( PEP 274 ) також працює з Python 2.7.
Арсеній

10

Інший спосіб розширити відповідь Іллі Прокіна - насправді використовувати reversedфункцію.

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

По суті, ваш словник повторюється (використовуючи .items()), де кожен елемент є парою ключ / значення, і ці елементи замінюються reversedфункцією. Коли це передається dictконструктору, він перетворює їх у пари значення / ключ, що саме вам потрібно.


6

Пропозиція щодо вдосконалення відповіді Хав'єра:

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

Замість цього d.keys()ви можете писати просто d, тому що якщо ви пройдете словник за допомогою ітератора, він поверне ключі відповідного словника.

Вих. для такої поведінки:

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


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

.items()повертає список кортежів (key, value). map()проходить через елементи списку і застосовує lambda x:[::-1]до кожного його елемента (кортежу), щоб повернути його назад, тому кожен кортеж потрапляє (value, key)до нового списку, виплюнутого з карти. Нарешті,dict() робить постанову з нового списку.


.items () повертає список кортежів (ключ, значення). map () проходить через елементи списку і застосовує lambda x:[::-1]до кожного його елемента (кортежу), щоб повернути його назад, тому кожен кортеж стає (значенням, ключем) у новому списку, виплескуваним із карти. Нарешті, dict () складає dict з нового списку.
Ілля Прокін

1

Використовуючи цикл : -

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

Додавання рішення на місці:

>>> 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}

У Python3 надзвичайно важливо використовувати, list(d.keys())оскільки dict.keysповертає подання клавіш. Якщо ви використовуєте Python2, d.keys()досить.


1

Відповідь Ханана є правильною, оскільки вона охоплює більш загальний випадок (інші відповіді є свого роду оманливими для тих, хто не знає про ситуацію, що повторюється). Поліпшенням відповіді Ханана є використання 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]}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.