사전에있는 값을 알고 키를 찾는 간단한 방법이 있습니까?
내가 생각할 수있는 것은 이것뿐입니다.
key = [key for key, value in dict_obj.items() if value == 'value'][0]
답변
없습니다. 값은 0 또는 1보다 많은 키를 포함하여 여러 키에서 찾을 수 있음을 잊지 마십시오.
답변
목록 이해력은 모든 일치 항목을 찾는 모든 사전 항목을 살펴본 다음 첫 번째 키를 반환합니다. 이 생성기 표현식은 첫 번째 값을 반환하는 데 필요한만큼만 반복합니다.
key = next(key for key, value in dd.items() if value == 'value')
dd
사전은 어디에 있습니까 ? 올릴 StopIteration
일치하는 항목이없는 경우 해당 잡을처럼 더 적절한 예외를 반환 할 수 있도록, ValueError
또는 KeyError
.
답변
사전이 일대일 매핑 인 경우가 있습니다.
예 :
d = {1: "one", 2: "two" ...}
단일 조회 만 수행하는 경우 접근 방식이 괜찮습니다. 그러나 둘 이상의 조회를 수행해야하는 경우 역 사전을 만드는 것이 더 효율적입니다.
ivd = {v: k for k, v in d.items()}
동일한 값을 가진 여러 키가있을 가능성이있는 경우이 경우 원하는 동작을 지정해야합니다.
Python이 2.6 이상인 경우 다음을 사용할 수 있습니다.
ivd = dict((v, k) for k, v in d.items())
답변
이 버전은 귀하의 버전보다 26 % 더 짧지 만 중복 / 모호한 값의 경우에도 동일하게 작동합니다 (귀하의 것과 같이 첫 번째 일치 항목을 반환 함). 그러나 dict에서 두 번 목록을 생성하기 때문에 아마도 두 배 느릴 것입니다.
key = dict_obj.keys()[dict_obj.values().index(value)]
또는 가독성보다 간결함을 선호하는 경우
key = list(dict_obj)[dict_obj.values().index(value)]
효율성을 선호한다면 @PaulMcGuire의 접근 방식 이 더 좋습니다. 동일한 값을 공유하는 키가 많은 경우 목록 이해로 해당 키 목록을 인스턴스화하지 않고 대신 생성기를 사용하는 것이 더 효율적입니다.
key = (key for key, value in dict_obj.items() if value == 'value').next()
답변
이것은 여전히 매우 관련이 있기 때문에 첫 번째 Google 히트작이며이 문제를 파악하는 데 약간의 시간을 할애하므로 (Python 3에서 작업하는) 솔루션을 게시 할 것입니다.
testdict = {'one' : '1',
'two' : '2',
'three' : '3',
'four' : '4'
}
value = '2'
[key for key in testdict.items() if key[1] == value][0][0]
Out[1]: 'two'
일치하는 첫 번째 값을 제공합니다.
답변
아마도 DoubleDict
아래와 같은 사전과 같은 클래스 가 당신이 원하는 것일까 요? 제공된 메타 클래스 중 하나를 메타 클래스와 함께 사용 DoubleDict
하거나 사용하지 않을 수 있습니다.
import functools
import threading
################################################################################
class _DDChecker(type):
def __new__(cls, name, bases, classdict):
for key, value in classdict.items():
if key not in {'__new__', '__slots__', '_DoubleDict__dict_view'}:
classdict[key] = cls._wrap(value)
return super().__new__(cls, name, bases, classdict)
@staticmethod
def _wrap(function):
@functools.wraps(function)
def check(self, *args, **kwargs):
value = function(self, *args, **kwargs)
if self._DoubleDict__forward != \
dict(map(reversed, self._DoubleDict__reverse.items())):
raise RuntimeError('Forward & Reverse are not equivalent!')
return value
return check
################################################################################
class _DDAtomic(_DDChecker):
def __new__(cls, name, bases, classdict):
if not bases:
classdict['__slots__'] += ('_DDAtomic__mutex',)
classdict['__new__'] = cls._atomic_new
return super().__new__(cls, name, bases, classdict)
@staticmethod
def _atomic_new(cls, iterable=(), **pairs):
instance = object.__new__(cls, iterable, **pairs)
instance.__mutex = threading.RLock()
instance.clear()
return instance
@staticmethod
def _wrap(function):
@functools.wraps(function)
def atomic(self, *args, **kwargs):
with self.__mutex:
return function(self, *args, **kwargs)
return atomic
################################################################################
class _DDAtomicChecker(_DDAtomic):
@staticmethod
def _wrap(function):
return _DDAtomic._wrap(_DDChecker._wrap(function))
################################################################################
class DoubleDict(metaclass=_DDAtomicChecker):
__slots__ = '__forward', '__reverse'
def __new__(cls, iterable=(), **pairs):
instance = super().__new__(cls, iterable, **pairs)
instance.clear()
return instance
def __init__(self, iterable=(), **pairs):
self.update(iterable, **pairs)
########################################################################
def __repr__(self):
return repr(self.__forward)
def __lt__(self, other):
return self.__forward < other
def __le__(self, other):
return self.__forward <= other
def __eq__(self, other):
return self.__forward == other
def __ne__(self, other):
return self.__forward != other
def __gt__(self, other):
return self.__forward > other
def __ge__(self, other):
return self.__forward >= other
def __len__(self):
return len(self.__forward)
def __getitem__(self, key):
if key in self:
return self.__forward[key]
return self.__missing_key(key)
def __setitem__(self, key, value):
if self.in_values(value):
del self[self.get_key(value)]
self.__set_key_value(key, value)
return value
def __delitem__(self, key):
self.pop(key)
def __iter__(self):
return iter(self.__forward)
def __contains__(self, key):
return key in self.__forward
########################################################################
def clear(self):
self.__forward = {}
self.__reverse = {}
def copy(self):
return self.__class__(self.items())
def del_value(self, value):
self.pop_key(value)
def get(self, key, default=None):
return self[key] if key in self else default
def get_key(self, value):
if self.in_values(value):
return self.__reverse[value]
return self.__missing_value(value)
def get_key_default(self, value, default=None):
return self.get_key(value) if self.in_values(value) else default
def in_values(self, value):
return value in self.__reverse
def items(self):
return self.__dict_view('items', ((key, self[key]) for key in self))
def iter_values(self):
return iter(self.__reverse)
def keys(self):
return self.__dict_view('keys', self.__forward)
def pop(self, key, *default):
if len(default) > 1:
raise TypeError('too many arguments')
if key in self:
value = self[key]
self.__del_key_value(key, value)
return value
if default:
return default[0]
raise KeyError(key)
def pop_key(self, value, *default):
if len(default) > 1:
raise TypeError('too many arguments')
if self.in_values(value):
key = self.get_key(value)
self.__del_key_value(key, value)
return key
if default:
return default[0]
raise KeyError(value)
def popitem(self):
try:
key = next(iter(self))
except StopIteration:
raise KeyError('popitem(): dictionary is empty')
return key, self.pop(key)
def set_key(self, value, key):
if key in self:
self.del_value(self[key])
self.__set_key_value(key, value)
return key
def setdefault(self, key, default=None):
if key not in self:
self[key] = default
return self[key]
def setdefault_key(self, value, default=None):
if not self.in_values(value):
self.set_key(value, default)
return self.get_key(value)
def update(self, iterable=(), **pairs):
for key, value in (((key, iterable[key]) for key in iterable.keys())
if hasattr(iterable, 'keys') else iterable):
self[key] = value
for key, value in pairs.items():
self[key] = value
def values(self):
return self.__dict_view('values', self.__reverse)
########################################################################
def __missing_key(self, key):
if hasattr(self.__class__, '__missing__'):
return self.__missing__(key)
if not hasattr(self, 'default_factory') \
or self.default_factory is None:
raise KeyError(key)
return self.__setitem__(key, self.default_factory())
def __missing_value(self, value):
if hasattr(self.__class__, '__missing_value__'):
return self.__missing_value__(value)
if not hasattr(self, 'default_key_factory') \
or self.default_key_factory is None:
raise KeyError(value)
return self.set_key(value, self.default_key_factory())
def __set_key_value(self, key, value):
self.__forward[key] = value
self.__reverse[value] = key
def __del_key_value(self, key, value):
del self.__forward[key]
del self.__reverse[value]
########################################################################
class __dict_view(frozenset):
__slots__ = '__name'
def __new__(cls, name, iterable=()):
instance = super().__new__(cls, iterable)
instance.__name = name
return instance
def __repr__(self):
return 'dict_{}({})'.format(self.__name, list(self))
답변
아니요, 모든 키를 확인하고 모든 값을 확인하지 않고는이 작업을 효율적으로 수행 할 수 없습니다. 따라서 O(n)
이를 수행 하려면 시간이 필요합니다. 이러한 조회를 많이 수행해야하는 경우 역전 된 사전을 구성한 다음 (에서도 수행 할 수 있음 O(n)
)이 역전 된 사전 내에서 검색 을 수행하여 효율적으로 수행해야합니다 (각 검색은 평균적으로 소요됩니다 O(1)
).
다음은 일반 사전에서 역전 된 사전 (일대 다 매핑을 수행 할 수 있음)을 구성하는 방법의 예입니다.
for i in h_normal:
for j in h_normal[i]:
if j not in h_reversed:
h_reversed[j] = set([i])
else:
h_reversed[j].add(i)
예를 들어
h_normal = {
1: set([3]),
2: set([5, 7]),
3: set([]),
4: set([7]),
5: set([1, 4]),
6: set([1, 7]),
7: set([1]),
8: set([2, 5, 6])
}
너의 h_reversed
의지는
{
1: set([5, 6, 7]),
2: set([8]),
3: set([1]),
4: set([5]),
5: set([8, 2]),
6: set([8]),
7: set([2, 4, 6])
}