ให้พจนานุกรมเช่น:
my_map = {'a': 1, 'b': 2}
วิธีหนึ่งสามารถพลิกแผนที่นี้เพื่อรับ:
inv_map = {1: 'a', 2: 'b'}
ให้พจนานุกรมเช่น:
my_map = {'a': 1, 'b': 2}
วิธีหนึ่งสามารถพลิกแผนที่นี้เพื่อรับ:
inv_map = {1: 'a', 2: 'b'}
คำตอบ:
สำหรับ Python 2.7.x
inv_map = {v: k for k, v in my_map.iteritems()}
สำหรับ 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
. ไม่มีการรับประกันว่าจะอยู่ทางนั้นจึงไม่เขียนโค้ดอาศัยไม่เป็นมีพฤติกรรมเช่นเดียวกับDict
OrderedDict
สมมติว่าค่าใน dict นั้นไม่ซ้ำกัน:
dict((v, k) for k, v in my_map.iteritems())
iteritems()
จะส่งออกดังนั้นจึงอาจสันนิษฐานได้ว่าจะมีการกำหนดคีย์ที่กำหนดเองให้กับค่าที่ไม่ซ้ำกันในลักษณะที่จะทำซ้ำได้อย่างชัดเจนภายใต้เงื่อนไขบางประการ แต่ไม่มีโดยทั่วไป
iteritems()
วิธีการอีกต่อไปและวิธีนี้จะไม่ทำงาน ใช้ที่items()
นั่นแทนดังที่แสดงในคำตอบที่ยอมรับ dict
นอกจากนี้ยังมีความเข้าใจในพจนานุกรมจะทำให้สวยกว่านี้โทร
หากค่าในmy_map
นั้นไม่ซ้ำกัน:
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, [])
ส่งคืนรายการที่เพิ่มไว้แล้วหากมีอยู่ดังนั้นการมอบหมายไม่ได้รีเซ็ตเป็นรายการว่าง setdefault
จะยังคงสวยกว่านี้
inv_map.setdefault(v, set()).add(k)
.
my_map.items()
my_map.iteritems()
ในการทำเช่นนี้ในขณะที่ยังคงรักษาประเภทของการแมปของคุณไว้ (สมมติว่ามันเป็นคลาสย่อยdict
หรือdict
):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
ลองสิ่งนี้:
inv_map = dict(zip(my_map.values(), my_map.keys()))
(โปรดทราบว่าเอกสาร Python ในมุมมองพจนานุกรมรับประกันอย่างชัดเจน.keys()
และ.values()
มีองค์ประกอบในลำดับเดียวกันซึ่งช่วยให้วิธีการด้านบนทำงานได้)
อีกวิธีหนึ่งคือ:
inv_map = dict((my_map[k], k) for k in my_map)
หรือใช้ความเข้าใจพจน์ของ python 3.0
inv_map = {my_map[k] : k for k in my_map}
อีกวิธีที่ทำงานได้มากขึ้น:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
filter
และmap
ควรตายและถูกนำไปรวมไว้ในรายการความเข้าใจ
dict
กับการทำแผนที่ประเภทอื่น ๆ เช่นcollections.OrderedDict
หรือcollections.defaultdict
สิ่งนี้จะขยายออกไปตามคำตอบของโรเบิร์ตซึ่งนำไปใช้กับเมื่อค่าใน dict นั้นไม่ซ้ำกัน
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
การใช้งานมีข้อ จำกัด ในการที่คุณไม่สามารถใช้reversed
สองครั้งและได้รับต้นฉบับ มันไม่สมมาตรเช่นนี้ ผ่านการทดสอบกับ Python 2.6 นี่คือกรณีการใช้งานของวิธีการที่ฉันใช้ในการพิมพ์ผลลัพธ์ dict
ถ้าคุณต้องการใช้set
กว่าlist
และมีการใช้งานอยู่สามารถเรียงลำดับที่นี้ทำให้รู้สึกแทนการใช้setdefault(v, []).append(k)
setdefault(v, set()).add(k)
revdict.setdefault(v, set()).add(k)
set
ของเหตุผลที่มันเป็นเหตุผลที่ดีที่จะใช้ เป็นประเภทที่แท้จริงที่ใช้ที่นี่ จะทำอย่างไรถ้าฉันต้องการหากุญแจทั้งหมดที่มีค่า1
หรือ2
ไม่ จากนั้นฉันก็ทำได้d.keys() - inv_d[1] - inv_d[2]
(ใน Python 3)
นอกจากนี้เรายังสามารถย้อนกลับพจนานุกรมด้วยคีย์ซ้ำโดยใช้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']}
ดูที่นี่ :
dict.setdefault()
เทคนิคนี้จะง่ายและเร็วกว่าเทคนิคการใช้เทียบเท่า
ตัวอย่างเช่นคุณมีพจนานุกรมต่อไปนี้:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
และคุณต้องการที่จะได้มันในรูปแบบฤ:ษี:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
โซลูชั่นแรก สำหรับการย้อนกลับคู่คีย์ - ค่าในพจนานุกรมของคุณให้ใช้for
วิธี -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)
โซลูชั่นที่สอง ใช้แนวทางความเข้าใจในพจนานุกรมสำหรับการกลับรายการ:
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
โซลูชั่นที่สาม ใช้การย้อนกลับวิธีการกลับรายการ (อาศัยโซลูชันที่สอง):
# 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
สงวนไว้และไม่ควรใช้สำหรับชื่อตัวแปร
my_map
คืออะไร
dictio()
? คุณหมายถึงdict()
อะไร
การรวมกันของรายการและความเข้าใจในพจนานุกรม สามารถจัดการกับกุญแจที่ซ้ำกัน
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
หากค่าไม่ซ้ำกันและคุณเป็นคนง่าย ๆ เล็กน้อย:
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())
)
โดยเฉพาะอย่างยิ่งสำหรับ dict ขนาดใหญ่โปรดทราบว่าวิธีนี้มีประสิทธิภาพน้อยกว่าคำตอบที่Python ย้อนกลับ / กลับการแม็พเนื่องจากมันวนซ้ำitems()
หลายครั้ง
-1
เพราะมันยังคงตอบคำถามเพียงความเห็นของฉัน
นอกเหนือจากฟังก์ชั่นอื่น ๆ ที่แนะนำข้างต้นหากคุณชอบ lambdas:
invert = lambda mydict: {v:k for k, v in mydict.items()}
หรือคุณสามารถทำได้ด้วยวิธีนี้เช่นกัน:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
ฉันคิดว่าวิธีที่ดีที่สุดในการทำเช่นนี้คือการกำหนดชั้นเรียน นี่คือการดำเนินการของ "พจนานุกรมสมมาตร":
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
วิธีการลบและการทำซ้ำนั้นง่ายพอที่จะนำไปใช้หากต้องการ
การนำไปใช้นี้มีประสิทธิภาพมากกว่าการสลับทั้งพจนานุกรม (ซึ่งน่าจะเป็นคำตอบที่ได้รับความนิยมมากที่สุดในหน้านี้) ไม่ต้องพูดถึงคุณสามารถเพิ่มหรือลบค่าออกจาก SymDict ของคุณได้มากเท่าที่คุณต้องการและ Inverse-dictionary ของคุณจะยังคงใช้งานได้อยู่เสมอ - สิ่งนี้ไม่เป็นความจริงถ้าคุณย้อนกลับทั้งพจนานุกรมหนึ่งครั้ง
dictresize
แต่วิธีนี้ปฏิเสธ Python ที่เป็นไปได้
วิธีนี้จะจัดการกับค่าที่ไม่ซ้ำกันและรักษาลักษณะส่วนใหญ่ของกรณีที่ไม่ซ้ำกัน
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
สำหรับงูหลาม 3.x แทนที่ด้วยitervalues
values
ฟังก์ชั่นเป็นสมมาตรสำหรับค่าของรายการประเภท; สิ่งอันดับจะถูก coverted กับรายการเมื่อดำเนินการ reverse_dict (reverse_dict (พจนานุกรม))
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
เนื่องจากพจนานุกรมต้องการคีย์ที่ไม่ซ้ำกันหนึ่งรายการในพจนานุกรมซึ่งแตกต่างจากค่าเราจึงต้องผนวกค่าที่กลับรายการในรายการการเรียงลำดับเพื่อรวมไว้ในคีย์เฉพาะใหม่
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
วิธีแก้ปัญหาการทำงานที่รวดเร็วสำหรับแผนที่ที่ไม่ใช่ Bijective (ค่าไม่ซ้ำกัน):
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
)
}
ในทฤษฎีนี้ควรจะเร็วกว่าการเพิ่มชุด (หรือผนวกกับรายการ) หนึ่งโดยหนึ่งเช่นเดียวกับในการแก้ปัญหาความจำเป็น
น่าเสียดายที่ค่าจะต้องมีการเรียงลำดับ Groupby ต้องการการเรียงลำดับ
n
องค์ประกอบที่กำหนดใน dict ดั้งเดิมวิธีการของคุณมีO(n log n)
ความซับซ้อนของเวลาเนื่องจากจำเป็นต้องจัดเรียงรายการของ dict ในขณะที่แนวทางที่ไร้เดียงสามีO(n)
ความซับซ้อนของเวลา สำหรับทั้งหมดที่ฉันรู้วิธีการของคุณอาจเร็วขึ้นจนกว่าจะมีขนาดใหญ่ไร้สาระdict
ในทางปฏิบัติแต่แน่นอนว่ามันไม่เร็วกว่าในทางทฤษฎี
ลองทำเช่นนี้กับ python 2.7 / 3.x
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
ฉันจะทำอย่างนั้นในหลาม 2
inv_map = {my_map[x] : x for x in my_map}
dict.items
(หรือiteritems
ใน Python 2) จะมีประสิทธิภาพมากกว่าการแยกแต่ละค่าแยกต่างหากในขณะที่ทำซ้ำคีย์
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})
สิ่งนี้จะให้ผลลัพธ์เป็น: {1: ['a', 'd'], 2: ['b'], 3: ['c']}
dict.items
(หรือiteritems
ใน Python 2) จะมีประสิทธิภาพมากกว่าการแยกแต่ละค่าแยกต่างหากในขณะที่ทำซ้ำคีย์ นอกจากนี้คุณยังไม่ได้เพิ่มคำอธิบายสำหรับคำตอบที่ซ้ำกับคนอื่น
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
รหัสนี้ทำอย่างนี้:
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']}
ไม่ใช่สิ่งที่แตกต่างอย่างสิ้นเชิงเพียงสูตรการเขียนใหม่จากตำราอาหาร มันเป็นsetdefault
วิธีที่ได้รับการปรับให้เหมาะสมที่สุดโดยใช้วิธีการเก็บรักษาแทนการใช้แต่ละครั้งผ่านตัวอย่าง:
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)
ออกแบบมาเพื่อทำงานภายใต้ CPython 3.x สำหรับ 2.x แทนที่mapping.items()
ด้วยmapping.iteritems()
บนเครื่องของฉันทำงานเร็วขึ้นเล็กน้อยกว่าตัวอย่างอื่น ๆ ที่นี่
dict
และจากนั้นแปลงเป็นคลาสที่ต้องการในตอนท้าย (แทนที่จะเริ่มด้วยคลาสประเภทที่ถูกต้อง) ดูเหมือนว่าฉันจะได้รับประสิทธิภาพที่หลีกเลี่ยงได้อย่างสิ้นเชิงที่นี่
ฉันเขียนสิ่งนี้ด้วยความช่วยเหลือของวงจร 'for' และ method '.get ()' และฉันเปลี่ยนชื่อ 'map' ของพจนานุกรมเป็น 'map1' เพราะ 'map' เป็นฟังก์ชั่น
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
หากค่าไม่ซ้ำกันและอาจเป็นแฮช (หนึ่งส่วนข้อมูล):
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)
และด้วยการเรียกซ้ำถ้าคุณต้องการขุดให้ลึกกว่านั้นเพียงมิติเดียว:
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"}
เป็น{'b': ['foo'], 'a': ['foo'], 'r': ['foo']}
และยกข้อยกเว้นหากค่าใด ๆ ในmyDict
นั้นไม่สามารถทำซ้ำได้ ฉันไม่แน่ใจว่าพฤติกรรมที่คุณพยายามนำมาใช้ที่นี่ แต่สิ่งที่คุณนำมาใช้จริงเป็นสิ่งที่ไม่มีใครต้องการ
my_map.items()
ทำงานได้ดี