Diberikan kamus seperti ini:
my_map = {'a': 1, 'b': 2}
Bagaimana seseorang membalik peta ini untuk mendapatkan:
inv_map = {1: 'a', 2: 'b'}
Diberikan kamus seperti ini:
my_map = {'a': 1, 'b': 2}
Bagaimana seseorang membalik peta ini untuk mendapatkan:
inv_map = {1: 'a', 2: 'b'}
Jawaban:
Untuk Python 2.7.x
inv_map = {v: k for k, v in my_map.iteritems()}
Untuk Python 3+:
inv_map = {v: k for k, v in my_map.items()}
The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon
. Tidak ada jaminan itu akan tetap seperti itu jadi jangan menulis kode dengan mengandalkan Dict
perilaku yang sama OrderedDict
.
Dengan asumsi bahwa nilai dalam dikt adalah unik:
dict((v, k) for k, v in my_map.iteritems())
iteritems()
akan dihasilkan, sehingga dapat diasumsikan bahwa kunci arbitrer akan diberikan untuk nilai yang tidak unik, dengan cara yang tampaknya akan dapat diproduksi kembali dalam beberapa kondisi, tetapi tidak demikian pada umumnya.
iteritems()
metode dan pendekatan ini tidak akan berfungsi; gunakan di items()
sana sebagai gantinya ditunjukkan pada jawaban yang diterima. Juga, pemahaman kamus akan membuat ini lebih cantik daripada menelepon dict
.
Jika nilai dalam my_map
tidak unik:
inv_map = {}
for k, v in my_map.iteritems():
inv_map[v] = inv_map.get(v, [])
inv_map[v].append(k)
inv_map.get(v, [])
mengembalikan daftar yang sudah ditambahkan jika ada, sehingga tugas tidak diatur ulang ke daftar kosong. setdefault
masih akan lebih cantik.
inv_map.setdefault(v, set()).add(k)
.
my_map.items()
sebagai ganti my_map.iteritems()
.
Untuk melakukan ini sambil mempertahankan jenis pemetaan Anda (dengan asumsi bahwa itu adalah dict
atau dict
subkelas):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
Coba ini:
inv_map = dict(zip(my_map.values(), my_map.keys()))
(Perhatikan bahwa dokumentasi Python pada tampilan kamus secara eksplisit menjamin hal itu .keys()
dan .values()
elemen-elemennya dalam urutan yang sama, yang memungkinkan pendekatan di atas berfungsi.)
Kalau tidak:
inv_map = dict((my_map[k], k) for k in my_map)
atau menggunakan pemahaman dict python 3.0
inv_map = {my_map[k] : k for k in my_map}
Cara lain yang lebih fungsional:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
filter
dan map
harus mati dan dimasukkan ke dalam daftar pemahaman, bukan menumbuhkan lebih banyak varian".
dict
dengan tipe pemetaan lain seperti collections.OrderedDict
ataucollections.defaultdict
Ini memperluas jawaban oleh Robert , berlaku ketika nilai-nilai dalam dikt tidak unik.
class ReversibleDict(dict):
def reversed(self):
"""
Return a reversed dict, with common values in the original dict
grouped into a list in the returned dict.
Example:
>>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
>>> d.reversed()
{1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']}
"""
revdict = {}
for k, v in self.iteritems():
revdict.setdefault(v, []).append(k)
return revdict
Implementasinya terbatas karena Anda tidak dapat menggunakan reversed
dua kali dan mendapatkan yang asli kembali. Itu tidak simetris seperti itu. Ini diuji dengan Python 2.6. Berikut ini adalah contoh penggunaan tentang bagaimana saya menggunakan untuk mencetak dict yang dihasilkan.
Jika Anda lebih suka menggunakan a set
daripada a list
, dan mungkin ada aplikasi yang tidak diurutkan yang artinya ini masuk akal, alih-alih setdefault(v, []).append(k)
digunakan setdefault(v, set()).add(k)
.
revdict.setdefault(v, set()).add(k)
set
. Ini adalah tipe intrinsik yang berlaku di sini. Bagaimana jika saya ingin menemukan semua kunci di mana nilainya tidak 1
atau 2
? Maka saya bisa melakukan d.keys() - inv_d[1] - inv_d[2]
(dalam Python 3)
Kami juga dapat membalikkan kamus dengan kunci duplikat menggunakan defaultdict
:
from collections import Counter, defaultdict
def invert_dict(d):
d_inv = defaultdict(list)
for k, v in d.items():
d_inv[v].append(k)
return d_inv
text = 'aaa bbb ccc ddd aaa bbb ccc aaa'
c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1})
dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']}
Lihat di sini :
Teknik ini lebih sederhana dan lebih cepat daripada menggunakan teknik setara
dict.setdefault()
.
Misalnya, Anda memiliki kamus berikut:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
Dan Anda ingin mendapatkannya dalam bentuk terbalik:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
Solusi Pertama . Untuk membalikkan pasangan nilai kunci dalam kamus Anda, gunakan for
pendekatan -loop:
# Use this code to invert dictionaries that have non-unique values
inverted_dict = dict()
for key, value in dict.items():
inverted_dict.setdefault(value, list()).append(key)
Solusi Kedua . Gunakan pendekatan pemahaman kamus untuk inversi:
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
Solusi Ketiga . Gunakan membalikkan pendekatan inversi (bergantung pada solusi kedua):
# Use this code to invert dictionaries that have lists of values
dict = {value: key for key in inverted_dict for value in my_map[key]}
dict
dicadangkan dan tidak boleh digunakan untuk nama variabel
my_map
yang
dictio()
? Apakah maksud Anda dict()
?
Kombinasi pemahaman daftar dan kamus. Dapat menangani kunci duplikat
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
Jika nilainya tidak unik, dan Anda sedikit hardcore:
inv_map = dict(
(v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())])
for v in set(my_map.values())
)
Khusus untuk dikt besar, perhatikan bahwa solusi ini jauh lebih efisien daripada jawaban Python membalikkan / membalikkan pemetaan karena berulang items()
kali berulang.
-1
karena masih menjawab pertanyaan, hanya pendapat saya.
Selain fungsi-fungsi lain yang disarankan di atas, jika Anda suka lambdas:
invert = lambda mydict: {v:k for k, v in mydict.items()}
Atau, Anda bisa melakukannya dengan cara ini juga:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
Saya pikir cara terbaik untuk melakukan ini adalah dengan mendefinisikan kelas. Berikut ini adalah implementasi dari "kamus simetris":
class SymDict:
def __init__(self):
self.aToB = {}
self.bToA = {}
def assocAB(self, a, b):
# Stores and returns a tuple (a,b) of overwritten bindings
currB = None
if a in self.aToB: currB = self.bToA[a]
currA = None
if b in self.bToA: currA = self.aToB[b]
self.aToB[a] = b
self.bToA[b] = a
return (currA, currB)
def lookupA(self, a):
if a in self.aToB:
return self.aToB[a]
return None
def lookupB(self, b):
if b in self.bToA:
return self.bToA[b]
return None
Metode penghapusan dan iterasi cukup mudah untuk diterapkan jika diperlukan.
Implementasi ini jauh lebih efisien daripada membalik seluruh kamus (yang tampaknya menjadi solusi paling populer di halaman ini). Belum lagi, Anda dapat menambah atau menghapus nilai dari SymDict Anda sebanyak yang Anda inginkan, dan kamus terbalik Anda akan selalu tetap valid - ini tidak benar jika Anda hanya membalikkan seluruh kamus sekali saja.
dictresize
, tetapi pendekatan ini menolak Python kemungkinan itu.
Ini menangani nilai-nilai non-unik dan mempertahankan banyak tampilan kasing unik.
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Untuk Python 3.x, ganti itervalues
dengan values
.
Fungsi simetris untuk nilai daftar tipe; Tuples dilindungi ke daftar saat melakukan reverse_dict (reverse_dict (kamus))
def reverse_dict(dictionary):
reverse_dict = {}
for key, value in dictionary.iteritems():
if not isinstance(value, (list, tuple)):
value = [value]
for val in value:
reverse_dict[val] = reverse_dict.get(val, [])
reverse_dict[val].append(key)
for key, value in reverse_dict.iteritems():
if len(value) == 1:
reverse_dict[key] = value[0]
return reverse_dict
Karena kamus memerlukan satu kunci unik dalam kamus tidak seperti nilai, kami harus menambahkan nilai yang dibalik ke dalam daftar pengurutan untuk dimasukkan dalam kunci spesifik baru.
def r_maping(dictionary):
List_z=[]
Map= {}
for z, x in dictionary.iteritems(): #iterate through the keys and values
Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key.
return Map
Solusi fungsional cepat untuk peta non-bijektif (nilai tidak unik):
from itertools import imap, groupby
def fst(s):
return s[0]
def snd(s):
return s[1]
def inverseDict(d):
"""
input d: a -> b
output : b -> set(a)
"""
return {
v : set(imap(fst, kv_iter))
for (v, kv_iter) in groupby(
sorted(d.iteritems(),
key=snd),
key=snd
)
}
Secara teori ini harus lebih cepat daripada menambahkan ke set (atau menambahkan ke daftar) satu per satu seperti dalam solusi imperatif .
Sayangnya nilai-nilai harus diurutkan, pengurutan diperlukan oleh groupby.
n
unsur-unsur dalam diktik asli, pendekatan Anda memiliki O(n log n)
kompleksitas waktu karena kebutuhan untuk mengurutkan item-item dict, sedangkan pendekatan imperatif naif memiliki O(n)
kompleksitas waktu. Sejauh yang saya tahu pendekatan Anda mungkin lebih cepat sampai besar bukan kepalang dict
dalam praktek , tetapi tentu saja tidak lebih cepat secara teori.
Saya akan melakukannya dengan python 2.
inv_map = {my_map[x] : x for x in my_map}
dict.items
(atau iteritems
dengan Python 2) lebih efisien daripada mengekstraksi setiap nilai secara terpisah saat iterasi kunci.
def invertDictionary(d):
myDict = {}
for i in d:
value = d.get(i)
myDict.setdefault(value,[]).append(i)
return myDict
print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})
Ini akan menghasilkan output sebagai: {1: ['a', 'd'], 2: ['b'], 3: ['c']}
dict.items
(atau iteritems
dengan Python 2) lebih efisien daripada mengekstraksi setiap nilai secara terpisah saat iterasi kunci. Juga, Anda tidak menambahkan penjelasan pada jawaban yang menduplikasi orang lain.
def reverse_dictionary(input_dict):
out = {}
for v in input_dict.values():
for value in v:
if value not in out:
out[value.lower()] = []
for i in input_dict:
for j in out:
if j in map (lambda x : x.lower(),input_dict[i]):
out[j].append(i.lower())
out[j].sort()
return out
kode ini suka ini:
r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})
print(r)
{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
Bukan sesuatu yang sama sekali berbeda, hanya resep yang ditulis ulang sedikit dari Cookbook. Lebih lanjut dioptimalkan dengan mempertahankan setdefault
metode, daripada setiap kali mendapatkannya melalui contoh:
def inverse(mapping):
'''
A function to inverse mapping, collecting keys with simillar values
in list. Careful to retain original type and to be fast.
>> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
>> inverse(d)
{1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
'''
res = {}
setdef = res.setdefault
for key, value in mapping.items():
setdef(value, []).append(key)
return res if mapping.__class__==dict else mapping.__class__(res)
Dirancang untuk dijalankan di bawah CPython 3.x, untuk 2.x ganti mapping.items()
denganmapping.iteritems()
Di komputer saya berjalan sedikit lebih cepat, daripada contoh lain di sini
dict
dan kemudian mengonversi ke kelas yang diinginkan di akhir (daripada memulai dengan kelas dari jenis yang tepat) tampak bagi saya seperti itu menimbulkan hit kinerja yang sepenuhnya dapat dihindari, di sini.
Saya menulis ini dengan bantuan siklus 'untuk' dan metode '.get ()' dan saya mengubah nama 'peta' dari kamus menjadi 'map1' karena 'peta' adalah fungsi.
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
Jika nilai tidak unik DAN mungkin berupa hash (satu dimensi):
for k, v in myDict.items():
if len(v) > 1:
for item in v:
invDict[item] = invDict.get(item, [])
invDict[item].append(k)
else:
invDict[v] = invDict.get(v, [])
invDict[v].append(k)
Dan dengan rekursi jika Anda perlu menggali lebih dalam maka hanya satu dimensi:
def digList(lst):
temp = []
for item in lst:
if type(item) is list:
temp.append(digList(item))
else:
temp.append(item)
return set(temp)
for k, v in myDict.items():
if type(v) is list:
items = digList(v)
for item in items:
invDict[item] = invDict.get(item, [])
invDict[item].append(k)
else:
invDict[v] = invDict.get(v, [])
invDict[v].append(k)
{"foo": "bar"}
ke {'b': ['foo'], 'a': ['foo'], 'r': ['foo']}
dan menimbulkan pengecualian jika nilai apa pun di myDict
dalamnya tidak dapat diubah. Saya tidak yakin perilaku apa yang Anda coba terapkan di sini, tetapi apa yang sebenarnya Anda implementasikan adalah sesuatu yang tidak diinginkan oleh banyak orang.
my_map.items()
berfungsi