Đưa ra một từ điển như vậy:
my_map = {'a': 1, 'b': 2}
Làm thế nào một người có thể đảo ngược bản đồ này để có được:
inv_map = {1: 'a', 2: 'b'}
Đưa ra một từ điển như vậy:
my_map = {'a': 1, 'b': 2}
Làm thế nào một người có thể đảo ngược bản đồ này để có được:
inv_map = {1: 'a', 2: 'b'}
Câu trả lời:
Đối với Python 2.7.x
inv_map = {v: k for k, v in my_map.iteritems()}
Đối với 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
. Không có gì đảm bảo nó sẽ giữ nguyên như vậy vì vậy đừng viết mã dựa trên Dict
việc có hành vi tương tự như OrderedDict
.
Giả sử rằng các giá trị trong dict là duy nhất:
dict((v, k) for k, v in my_map.iteritems())
iteritems()
sẽ xuất ra, do đó, có thể giả định rằng một khóa tùy ý sẽ được gán cho một giá trị không duy nhất, theo cách có thể tái tạo rõ ràng trong một số điều kiện, nhưng nói chung là không thể.
iteritems()
phương thức nữa và phương pháp này sẽ không hoạt động; sử dụngitems()
ở đó thay vì như trong câu trả lời được chấp nhận. Ngoài ra, một sự hiểu biết từ điển sẽ làm cho điều này đẹp hơn so với gọi dict
.
Nếu các giá trị my_map
không phải là duy nhất:
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, [])
trả về danh sách đã thêm nếu có, vì vậy bài tập không được đặt lại vào danh sách trống. setdefault
vẫn sẽ đẹp hơn
inv_map.setdefault(v, set()).add(k)
.
my_map.items()
thay vì my_map.iteritems()
.
Để làm điều này trong khi bảo tồn loại ánh xạ của bạn (giả sử rằng đó là một dict
hoặc một dict
lớp con):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
Thử cái này:
inv_map = dict(zip(my_map.values(), my_map.keys()))
(Lưu ý rằng các tài liệu Python trên chế độ xem từ điển đảm bảo rõ ràng .keys()
và .values()
có các phần tử của chúng theo cùng một thứ tự, cho phép cách tiếp cận ở trên hoạt động.)
Cách khác:
inv_map = dict((my_map[k], k) for k in my_map)
hoặc sử dụng nhận thức chính tả của python 3.0
inv_map = {my_map[k] : k for k in my_map}
Một cách khác, nhiều chức năng hơn:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
filter
và map
nên chết và được đưa vào danh sách hiểu, không phát triển thêm các biến thể".
dict
với các loại ánh xạ khác như collections.OrderedDict
hoặccollections.defaultdict
Điều này mở rộng dựa trên câu trả lời của Robert , áp dụng cho khi các giá trị trong chính tả không phải là duy nhất.
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
Việc triển khai bị hạn chế ở chỗ bạn không thể sử dụng reversed
hai lần và lấy lại bản gốc. Nó không đối xứng như vậy. Nó được thử nghiệm với Python 2.6. Đây là một trường hợp sử dụng về cách tôi đang sử dụng để in dict kết quả.
Nếu bạn muốn sử dụng set
hơn một list
, và có thể tồn tại các ứng dụng không có thứ tự mà điều này có ý nghĩa, thay vì setdefault(v, []).append(k)
sử dụng setdefault(v, set()).add(k)
.
revdict.setdefault(v, set()).add(k)
set
. Đó là loại nội tại áp dụng ở đây. Điều gì xảy ra nếu tôi muốn tìm tất cả các khóa trong đó các giá trị không 1
hoặc 2
? Sau đó tôi chỉ có thể làm d.keys() - inv_d[1] - inv_d[2]
(trong Python 3)
Chúng tôi cũng có thể đảo ngược một từ điển với các khóa trùng lặp bằng cách sử dụng 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']}
Xem tại đây :
Kỹ thuật này đơn giản và nhanh hơn kỹ thuật tương đương
dict.setdefault()
.
Chẳng hạn, bạn có từ điển sau:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
Và bạn muốn có được nó trong một hình thức đảo ngược như vậy:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
Giải pháp đầu tiên . Để đảo ngược các cặp khóa-giá trị trong từ điển của bạn, hãy sử dụng for
cách tiếp cận -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)
Giải pháp thứ hai . Sử dụng một cách tiếp cận hiểu từ điển cho đảo ngược:
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
Giải pháp thứ ba . Sử dụng hoàn nguyên phương pháp đảo ngược (dựa vào giải pháp thứ hai):
# 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
được bảo lưu và không nên được sử dụng cho tên biến
my_map
là gì
dictio()
? Ý bạn là dict()
sao
Kết hợp danh sách và hiểu từ điển. Có thể xử lý các khóa trùng lặp
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
Nếu các giá trị không phải là duy nhất và bạn hơi khó tính:
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())
)
Đặc biệt đối với một lệnh lớn, lưu ý rằng giải pháp này kém hiệu quả hơn nhiều so với câu trả lời Python đảo ngược / đảo ngược ánh xạ vì nó lặp đi lặp lại items()
nhiều lần.
-1
vì nó vẫn trả lời câu hỏi, chỉ là ý kiến của tôi.
Ngoài các chức năng khác được đề xuất ở trên, nếu bạn thích lambdas:
invert = lambda mydict: {v:k for k, v in mydict.items()}
Hoặc, bạn cũng có thể làm theo cách này:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
Tôi nghĩ cách tốt nhất để làm điều này là xác định một lớp. Đây là một triển khai của một "từ điển đối xứng":
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
Phương pháp xóa và lặp lại đủ dễ thực hiện nếu cần.
Việc thực hiện này hiệu quả hơn nhiều so với việc đảo ngược toàn bộ từ điển (dường như là giải pháp phổ biến nhất trên trang này). Chưa kể, bạn có thể thêm hoặc xóa các giá trị khỏi SymDict bao nhiêu tùy ý và từ điển nghịch đảo của bạn sẽ luôn có hiệu lực - điều này không đúng nếu bạn chỉ cần đảo ngược toàn bộ từ điển một lần.
dictresize
, nhưng cách tiếp cận này phủ nhận khả năng đó của Python.
Điều này xử lý các giá trị không duy nhất và giữ lại nhiều giao diện của trường hợp duy nhất.
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Đối với Python 3.x, thay thế itervalues
bằng values
.
Hàm đối xứng với các giá trị của danh sách kiểu; Các bộ dữ liệu được chuyển thành danh sách khi thực hiện Reverse_dict (Reverse_dict (dictionary))
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
Vì từ điển yêu cầu một khóa duy nhất trong từ điển không giống như các giá trị, chúng tôi phải nối các giá trị đảo ngược vào một danh sách sắp xếp để được bao gồm trong các khóa cụ thể mới.
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
Giải pháp chức năng nhanh cho bản đồ không sinh học (giá trị không phải là duy nhất):
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
)
}
Về lý thuyết, việc này sẽ nhanh hơn việc thêm vào tập hợp (hoặc nối thêm vào danh sách) từng lượt một như trong giải pháp bắt buộc .
Thật không may, các giá trị phải được sắp xếp, việc sắp xếp được yêu cầu bởi nhóm.
n
các yếu tố trong dict gốc, cách tiếp cận của bạn có O(n log n)
độ phức tạp về thời gian do nhu cầu sắp xếp các mục của dict, trong khi cách tiếp cận mệnh lệnh ngây thơ có O(n)
độ phức tạp về thời gian. Đối với tất cả tôi biết cách tiếp cận của bạn có thể nhanh hơn cho đến lớn ngớ ngẩn dict
s trong thực tế , nhưng chắc chắn nó không nhanh hơn là về mặt lý thuyết.
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})
Điều này sẽ cung cấp đầu ra dưới dạng: {1: ['a', 'd'], 2: ['b'], 3: ['c']}
dict.items
(hoặc iteritems
trong Python 2) hiệu quả hơn so với trích xuất từng giá trị một cách riêng biệt trong khi lặp lại các khóa. Ngoài ra, bạn đã thêm không có lời giải thích cho một câu trả lời trùng lặp với người khác.
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
mã này làm như thế này:
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']}
Không phải là một cái gì đó hoàn toàn khác, chỉ là một công thức viết lại một chút từ Cookbook. Nó được tối ưu hóa hơn nữa bằng setdefault
phương pháp giữ lại , thay vì mỗi lần đưa nó qua ví dụ:
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)
Được thiết kế để chạy dưới CPython 3.x, thay thế cho 2.x mapping.items()
bằngmapping.iteritems()
Trên máy của tôi chạy nhanh hơn một chút, so với các ví dụ khác ở đây
dict
và sau đó chuyển đổi sang lớp mong muốn ở cuối (thay vì bắt đầu với một loại đúng loại) có vẻ như tôi phát sinh một cú đánh hiệu suất hoàn toàn có thể tránh được, ở đây.
Tôi đã viết điều này với sự trợ giúp của chu trình 'cho' và phương thức '.get ()' và tôi đã thay đổi tên 'map' của từ điển thành 'map1' vì 'map' là một hàm.
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
Nếu các giá trị không phải là duy nhất VÀ có thể là hàm băm (một chiều):
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)
Và với một đệ quy nếu bạn cần đào sâu hơn thì chỉ cần một chiều:
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"}
thành {'b': ['foo'], 'a': ['foo'], 'r': ['foo']}
và đưa ra một ngoại lệ nếu bất kỳ giá trị nào trong đó myDict
không phải là một lần lặp. Tôi không chắc hành vi nào bạn đang cố gắng thực hiện ở đây, nhưng những gì bạn thực sự thực hiện là điều mà hầu như không ai muốn.
my_map.items()
cũng hoạt động tốt