Böyle bir sözlük verildi:
my_map = {'a': 1, 'b': 2}
Kişi bu haritayı nasıl tersine çevirebilir:
inv_map = {1: 'a', 2: 'b'}
Böyle bir sözlük verildi:
my_map = {'a': 1, 'b': 2}
Kişi bu haritayı nasıl tersine çevirebilir:
inv_map = {1: 'a', 2: 'b'}
Yanıtlar:
Python 2.7.x için
inv_map = {v: k for k, v in my_map.iteritems()}
Python 3+ için:
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
. Bu şekilde kalacağının garantisi yoktur, bu nedenle Dict
aynı davranışa sahip kod yazmayın OrderedDict
.
Diksiyondaki değerlerin benzersiz olduğunu varsayarsak:
dict((v, k) for k, v in my_map.iteritems())
iteritems()
çıkacak sipariş konusunda hiçbir garanti yoktur , bu nedenle, benzersiz olmayan bir değer için bazı koşullar altında görünüşte çoğaltılabilecek şekilde rastgele bir anahtarın atanacağı varsayılabilir, ancak genel olarak böyle değildir.
iteritems()
yöntem olmadığını ve bu yaklaşımın işe yaramayacağını unutmayın; items()
orada kabul edilen cevapta gösterildiği gibi kullanın . Ayrıca, bir sözlük anlama bunu aramaktan daha güzel hale getirecektir dict
.
İçindeki değerler my_map
benzersiz değilse:
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, [])
varsa eklenmiş listeyi döndürür, bu nedenle atama boş bir listeye sıfırlanmaz. setdefault
yine de daha güzel olurdu.
inv_map.setdefault(v, set()).add(k)
.
my_map.items()
yerine kullanın my_map.iteritems()
.
Eşlemenizin türünü korurken bunu yapmak için (bunun bir dict
veya dict
alt sınıf olduğunu varsayarak ):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
Bunu dene:
inv_map = dict(zip(my_map.values(), my_map.keys()))
( Sözlük görünümlerindeki Python belgelerinin aşağıdakileri açıkça garanti ettiğini .keys()
ve.values()
işe yukarıdaki yaklaşım verir aynı sırayla, kendi unsurlar var.)
Alternatif:
inv_map = dict((my_map[k], k) for k in my_map)
veya python 3.0'ın diksiyon anlamalarını kullanma
inv_map = {my_map[k] : k for k in my_map}
Başka, daha işlevsel bir yol:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
filter
ve map
ölmeli ve daha fazla varyantı büyütmek yerine liste anlayışlarına katılmalı".
dict
gibi diğer haritalama türleri ile takas edebilme faydası vardırcollections.OrderedDict
collections.defaultdict
Bu, Robert'ın cevabı üzerine genişleyerek , diksiyondaki değerlerin benzersiz olmadığı zamanlara başvuruyor.
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
Uygulama, reversed
iki kez kullanamayacağınız ve orijinali geri alamayacağınız için sınırlıdır . Bu şekilde simetrik değildir. Python 2.6 ile test edilmiştir. Buraya ben çıkan dicti yazdırmak için kullanıyorum nasıl kullanıldığı durumdur.
Bunun yerine bir kullanmayı tercih ediyorsanız set
bir daha list
ve bu yerine, mantıklı olan sırasız uygulamalar var var olabileceği setdefault(v, []).append(k)
, kullanım setdefault(v, set()).add(k)
.
revdict.setdefault(v, set()).add(k)
set
. Burada geçerli olan içsel tiptir. Hangi değerleri olmayan nerede tüm anahtarları bulmak istiyorsanız 1
veya 2
? Sonra sadece yapabilirim d.keys() - inv_d[1] - inv_d[2]
(Python 3'te)
Ayrıca, yinelenen tuşlarla sözlüğü tersine çevirebiliriz 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']}
Buraya bakın :
Bu teknik, eşdeğer bir teknikten daha basit ve daha hızlıdır
dict.setdefault()
.
Örneğin, şu sözlüğe sahipsiniz:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
Ve bunu tersine çevrilmiş bir biçimde elde etmek istersiniz:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
İlk Çözüm . Sözlüğünüzdeki anahtar / değer çiftlerini ters for
çevirmek için bir -loop yaklaşımı kullanın :
# 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)
İkinci Çözüm . Ters çevirme için sözlük anlama yaklaşımı kullanın :
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
Üçüncü Çözüm . Ters çevirme yaklaşımını geri döndürmeyi kullanın (ikinci çözüme dayanır):
# 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
ayrılmış ve değişken isimleri için kullanılmamalıdır
my_map
olduğunu söylemeyi unuttum
dictio()
? Bunu mu demek istediniz dict()
?
Liste ve sözlük anlama kombinasyonu. Yinelenen tuşları işleyebilir
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
Değerler benzersiz değilse ve biraz sert iseniz:
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())
)
Özellikle büyük bir dikte için, bu çözümün Python'un bir haritayı tersine çevirme / tersine çevirme cevabından çok daha az verimli olduğuna dikkat edin, çünkü items()
birden fazla kez döngü yapar .
-1
çünkü hala soruyu cevaplıyor, sadece benim düşüncem.
Yukarıda önerilen diğer işlevlere ek olarak, lambdasları seviyorsanız:
invert = lambda mydict: {v:k for k, v in mydict.items()}
Veya bunu şu şekilde yapabilirsiniz:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
Bunu yapmanın en iyi yolunun bir sınıf tanımlamak olduğunu düşünüyorum. İşte bir "simetrik sözlük" uygulaması:
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
Gerekirse silme ve yineleme yöntemleri uygulanacak kadar kolaydır.
Bu uygulama, tüm bir sözlüğü tersine çevirmekten çok daha etkilidir (bu sayfadaki en popüler çözüm gibi görünüyor). Bahsetmemek gerekirse, SymDict'inize istediğiniz kadar değer ekleyebilir veya kaldırabilirsiniz ve ters sözlüğünüz her zaman geçerli kalır - tüm sözlüğü bir kez ters çevirirseniz bu doğru değildir.
dictresize
, ancak bu yaklaşım olasılığı olduğunu Python inkar eder.
Bu, benzersiz olmayan değerleri işler ve benzersiz durumun görünümünü korur.
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Python 3.x için, yerini itervalues
ile values
.
İşlev, tür listesinin değerleri için simetriktir; Reverse_dict (reverse_dict (sözlük)) yaparken tuples listelere dahil edilir
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
Sözlükler, değerlerin aksine sözlükte benzersiz bir anahtar gerektirdiğinden, ters çevrilmiş değerleri yeni belirli anahtarların içine dahil edilecek bir sıralama listesine eklememiz gerekir.
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
İki yönlü olmayan haritalar için hızlı fonksiyonel çözüm (değerler benzersiz değil):
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
)
}
Teorik olarak, bu, zorunlu çözümdeki gibi kümeye (veya listeye eklenerek) tek tek eklenmekten daha hızlı olmalıdır .
Ne yazık ki değerler sıralanabilir olmalıdır, sıralama groupby tarafından gereklidir.
n
Orijinal diksiyondaki unsurlar göz önüne alındığında , yaklaşımınız O(n log n)
zorun maddelerini sıralama ihtiyacı nedeniyle zaman karmaşıklığına sahipken, saf emir yaklaşımının O(n)
zaman karmaşıklığı vardır. Tüm ı yaklaşımınız daha hızlı saçma sapan büyük dek olabilir biliyoruz dict
içinde s pratikte , ama kesinlikle teoride değil hızlıdır.
Bunu python 2'de yapardım.
inv_map = {my_map[x] : x for x in my_map}
dict.items
(veya iteritems
Python 2'de) yinelemek, anahtarları yinelerken her bir değeri ayrı ayrı ayıklamaktan daha etkilidir.
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})
Bu, çıktıyı şu şekilde sağlayacaktır: {1: ['a', 'd'], 2: ['b'], 3: ['c']}
dict.items
(veya iteritems
Python 2'de) yinelemek, anahtarları yinelerken her bir değeri ayrı ayrı ayıklamaktan daha etkilidir. Ayrıca, başkalarını çoğaltan bir cevaba açıklama eklemediniz.
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
bu kod şöyle:
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']}
Tamamen farklı bir şey değil, sadece Cookbook'un biraz yeniden yazılmış tarifi. Dahası setdefault
, her seferinde örnek üzerinden almak yerine, tutma yöntemi ile optimize edilir :
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)
2.x için değiştirin CPython 3.x altında çalıştırılmak üzere tasarlanan mapping.items()
ilemapping.iteritems()
Makinemdeki diğer örneklerden biraz daha hızlı çalışıyor
dict
ve daha sonra (doğru tipte bir sınıfla başlamak yerine) sonunda istenen sınıfa dönüştürmek, burada tamamen önlenebilir bir performans vuruşu yapmış gibi görünüyor.
Bunu 'for' ve method '.get ()' döngüsünün yardımıyla yazdım ve sözlüğün 'map' adını 'map1' olarak değiştirdim çünkü 'map' bir işlev.
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
Değerler benzersiz değilse VE bir karma (bir boyut) olabilir:
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)
Ve bir özyineleme ile daha derin kazmanız gerekiyorsa, sadece bir boyut:
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"}
için {'b': ['foo'], 'a': ['foo'], 'r': ['foo']}
ve herhangi bir değer varsa bir istisna yükseltir myDict
değil bir iterable olduğunu. Burada hangi davranışı uygulamaya çalıştığınızdan emin değilim, ama aslında uyguladığınız şey kimsenin istemeyeceği bir şey.
my_map.items()
çalışıyor