Python dictçok kullanışlı bir veri yapısıdır:
d = {'a': 1, 'b': 2}
d['a'] # get 1
Bazen değerlere göre de indekslemek istersiniz.
d[1] # get 'a'
Bu veri yapısını uygulamanın en verimli yolu hangisidir? Bunu yapmanın resmi bir yolu var mı?
Python dictçok kullanışlı bir veri yapısıdır:
d = {'a': 1, 'b': 2}
d['a'] # get 1
Bazen değerlere göre de indekslemek istersiniz.
d[1] # get 'a'
Bu veri yapısını uygulamanın en verimli yolu hangisidir? Bunu yapmanın resmi bir yolu var mı?
{1: ['a', 'A'], 2: 'b'}. Bunu yapmanın böyle bir yolu için cevabıma bakın.
Yanıtlar:
Burada, Python sözlüğündeki değerden anahtar bulma yönteminden dictesinlenilmiş ve aşağıdaki 2) ve 3) 'e izin verecek şekilde değiştirilmiş çift yönlü bir sınıf bulunmaktadır .
Bunu not et :
bd.inverse , standart dikte bddeğiştirildiğinde kendini otomatik olarak günceller .bd.inverse[value] bir daima liste ait keyöyle ki bd[key] == value.bidict modülünden farklı olarak burada aynı değere sahip 2 anahtarımız olabilir, bu çok önemlidir .Kod:
class bidict(dict):
def __init__(self, *args, **kwargs):
super(bidict, self).__init__(*args, **kwargs)
self.inverse = {}
for key, value in self.items():
self.inverse.setdefault(value,[]).append(key)
def __setitem__(self, key, value):
if key in self:
self.inverse[self[key]].remove(key)
super(bidict, self).__setitem__(key, value)
self.inverse.setdefault(value,[]).append(key)
def __delitem__(self, key):
self.inverse.setdefault(self[key],[]).remove(key)
if self[key] in self.inverse and not self.inverse[self[key]]:
del self.inverse[self[key]]
super(bidict, self).__delitem__(key)
Kullanım örneği:
bd = bidict({'a': 1, 'b': 2})
print(bd) # {'a': 1, 'b': 2}
print(bd.inverse) # {1: ['a'], 2: ['b']}
bd['c'] = 1 # Now two keys have the same value (= 1)
print(bd) # {'a': 1, 'c': 1, 'b': 2}
print(bd.inverse) # {1: ['a', 'c'], 2: ['b']}
del bd['c']
print(bd) # {'a': 1, 'b': 2}
print(bd.inverse) # {1: ['a'], 2: ['b']}
del bd['a']
print(bd) # {'b': 2}
print(bd.inverse) # {2: ['b']}
bd['b'] = 3
print(bd) # {'b': 3}
print(bd.inverse) # {2: [], 3: ['b']}
self[key]içinde __delitem__()tek olan value = self[key]bu tür aramalar için yeniden atama. Ama ... evet. Bu önemsiz. Saf harika için teşekkürler, Basj !
Aynı dikteyi anahtar, değer çiftini ters sırada ekleyerek kullanabilirsiniz.
d = {'a': 1, 'b': 2}
revd = dikte ([d.items () i içindeki i için (i) tersine çevrildi])
d. güncelleme (revd)
d.update( dict((d[k], k) for k in d) ).
dict((v, k) for (k, v) in d.items()). Her durumda, sen .update doğrudan çiftlerini de geçirebilir: d.update(reversed(i) for i in d.items()).
d={'a':1, 'b':2, 1: 'b'}
dict(map(reversed, a_dict.items())).
d.update(revd)Sonu görmezden gelen bu cevabın ilk iki satırı harika olduğu için, yine de bir olumlu oy düşünüyorum. Bunu biraz düşünelim.
Aşağıdaki kod parçası, ters çevrilebilir (önyargılı) bir harita uygular:
class BijectionError(Exception):
"""Must set a unique value in a BijectiveMap."""
def __init__(self, value):
self.value = value
msg = 'The value "{}" is already in the mapping.'
super().__init__(msg.format(value))
class BijectiveMap(dict):
"""Invertible map."""
def __init__(self, inverse=None):
if inverse is None:
inverse = self.__class__(inverse=self)
self.inverse = inverse
def __setitem__(self, key, value):
if value in self.inverse:
raise BijectionError(value)
self.inverse._set_item(value, key)
self._set_item(key, value)
def __delitem__(self, key):
self.inverse._del_item(self[key])
self._del_item(key)
def _del_item(self, key):
super().__delitem__(key)
def _set_item(self, key, value):
super().__setitem__(key, value)
Bu uygulamanın avantajı, inversea'nın özniteliğinin BijectiveMapyine a olmasıdır BijectiveMap. Bu nedenle, aşağıdaki gibi şeyler yapabilirsiniz:
>>> foo = BijectiveMap()
>>> foo['steve'] = 42
>>> foo.inverse
{42: 'steve'}
>>> foo.inverse.inverse
{'steve': 42}
>>> foo.inverse.inverse is foo
True
Ne yazık ki, en yüksek puan alan cevap bidictçalışmıyor.
Üç seçenek vardır:
Alt sınıf diktesi : Bir alt sınıf oluşturabilirsiniz dict, ancak dikkatli olun. Sen özel uygulamaları yazmak gerekir update, pop, initializer, setdefault. dictUygulamalar demiyorlar __setitem__. Bu nedenle en yüksek puan alan cevapta sorunlar vardır.
UserDict'ten Devral : Bu, tüm rutinlerin doğru şekilde çağrılması için yapılması dışında, tıpkı bir dikte gibidir. Kaputun altında, adı verilen bir öğede bir dikte kullanır data. Python Belgelerini okuyabilir veya Python 3'te çalışan yönlü bir listenin basit bir uygulamasını kullanabilirsiniz . Aynen dahil etmediğim için özür dilerim: Telif hakkından emin değilim.
Soyut Temel Sınıflardan Devralma : collections.abc'den devralmak, yeni bir sınıf için tüm doğru protokolleri ve uygulamaları edinmenize yardımcı olacaktır. Bu, aynı zamanda bir veritabanını şifreleyip önbelleğe alamadığı sürece çift yönlü bir sözlük için gereğinden fazla bir şeydir.
TL; DR - Kodunuz için bunu kullanın . Okuma Trey Hunner 'ın makale detayları için.
Bunun gibi bir şey, belki:
import itertools
class BidirDict(dict):
def __init__(self, iterable=(), **kwargs):
self.update(iterable, **kwargs)
def update(self, iterable=(), **kwargs):
if hasattr(iterable, 'iteritems'):
iterable = iterable.iteritems()
for (key, value) in itertools.chain(iterable, kwargs.iteritems()):
self[key] = value
def __setitem__(self, key, value):
if key in self:
del self[key]
if value in self:
del self[value]
dict.__setitem__(self, key, value)
dict.__setitem__(self, value, key)
def __delitem__(self, key):
value = self[key]
dict.__delitem__(self, key)
dict.__delitem__(self, value)
def __repr__(self):
return '%s(%s)' % (type(self).__name__, dict.__repr__(self))
Birden fazla anahtarın belirli bir değeri varsa, ne olmasını istediğinize karar vermelisiniz; Belirli bir çiftin çift yönlü olması, daha sonra yerleştirdiğiniz bir çift tarafından kolayca bozulabilir. Olası bir seçeneği uyguladım.
Misal :
bd = BidirDict({'a': 'myvalue1', 'b': 'myvalue2', 'c': 'myvalue2'})
print bd['myvalue1'] # a
print bd['myvalue2'] # b
dict([('a', 'b'), ('b', 'c')]); dict['b']-> 'c'anahtar yerine 'a'.
print bd['myvalue2']cevapları b, c(veya [b, c]veya (b, c)veya veya başka herhangi bir şeyi) nasıl yapabiliriz ?
Öncelikle, değer eşlemesinin anahtarının bire bir olduğundan emin olmalısınız, aksi takdirde çift yönlü bir harita oluşturmak mümkün değildir.
İkincisi, veri kümesi ne kadar büyük? Fazla veri yoksa 2 ayrı harita kullanın ve güncelleme sırasında ikisini de güncelleyin. Ya da daha iyisi, yerleşik güncelleme / silme özelliğine sahip, yalnızca 2 diktlik bir sarmalayıcı olan Bidict gibi mevcut bir çözümü kullanın .
Ancak veri kümesi büyükse ve 2 dikt tutmak istenmiyorsa:
Hem anahtar hem de değer sayısal ise, eşlemeye yaklaşmak için Enterpolasyon kullanma olasılığını göz önünde bulundurun. Anahtar-değer çiftlerinin büyük çoğunluğu eşleme işlevi (ve
ters işlevi) tarafından ele alınabiliyorsa , o zaman yalnızca aykırı değerleri haritalara kaydetmeniz gerekir.
Erişimin çoğu tek yönlü ise (anahtar-> değer),
uzay için zaman ticareti yapmak için ters haritayı aşamalı olarak oluşturmak tamamen uygundur .
Kod:
d = {1: "one", 2: "two" }
reverse = {}
def get_key_by_value(v):
if v not in reverse:
for _k, _v in d.items():
if _v == v:
reverse[_v] = _k
break
return reverse[v]