Доступ к значениям ключа Python с символами запуска ключа

Мне было интересно: возможно ли получить доступ к значениям dict с помощью незавершенных ключей (если для данной строки не более одной записи)? Например:

my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
print my_dict['Date']
>> '15th july'

Возможно ли это? Как это можно сделать?

Ответ 1

Вы не можете сделать это напрямую с помощью dict[keyword], вам нужно выполнить итерацию по dict и сопоставить каждый ключ с ключевым словом и вернуть соответствующее значение, если ключевое слово найдено. Это будет операция O(N).

>>> my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
>>> next(v for k,v in my_dict.items() if 'Date' in k)
'15th july'

Чтобы получить все такие значения, используйте понимание списка:

>>> [ v for k,v in my_dict.items() if 'Date' in k]
['15th july']

используйте str.startswith, если вам нужны только те значения, ключи которых начинаются с 'Date':

>>> next( v for k,v in my_dict.items() if k.startswith('Date'))
'15th july'
>>> [ v for k,v in my_dict.items() if k.startswith('Date')]
['15th july']

Ответ 2

не лучшее решение, может быть улучшено (overide getitem)

class mydict(dict):
    def __getitem__(self, value):
        keys = [k for k in self.keys() if value in k]
        key = keys[0] if keys else None
        return self.get(key)


my_dict = mydict({'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'})
print(my_dict['Date'])# returns 15th july

Ответ 3

Конечно, это возможно:

print next(val for key, val in my_dict.iteritems() if key.startswith('Date'))

но это требует полного сканирования через словарь. Он находит только первый такой ключ соответствия (где "первый" является произвольным) и поднимает StopIteration вместо KeyError, если никакие клавиши не совпадают.

Чтобы приблизиться к тому, о чем вы думаете, лучше написать это как функцию:

def value_by_key_prefix(d, partial):
    matches = [val for key, val in d.iteritems() if key.startswith(partial)]
    if not matches:
        raise KeyError(partial)
    if len(matches) > 1:
        raise ValueError('{} matches more than one key'.format(partial))
    return matches[0]

Ответ 4

>>> my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
>>> next(v for k,v in my_dict.items() if 'Date' in k)
'15th july'


>>> [ v for k,v in my_dict.items() if 'Date' in k]
['15th july']


>>> next( v for k,v in my_dict.items() if k.startswith('Date'))
'15th july'
>>> [ v for k,v in my_dict.items() if k.startswith('Date')]
['15th july']

если я использую вышеуказанный метод, я получаю исключение StopIteration

Ответ 5

Вы не предлагаете когерентный API:

  • Что должно быть результатом my_dict['']? У вас нет сопоставления "один-к-одному".
  • Как он должен распространяться на типы, отличные от str?

Другая причина, по которой вы не можете получить ее напрямую, даже для строк и предполагая, что вы всегда возвращаете список, заключается в том, что Python dict реализуется с использованием хеш-таблицы и отображает xy и xz в несвязанные ячейки в таблице.

Итак, иными словами: такой поиск будет означать медленную реализацию dict (что не имеет смысла, оптимизация для необычного использования) или медленнее, чем полное сканирование, которое вы также можете написать его вручную, так как это не так уж и важно, чтобы использовать специальный метод удобства.

Ответ 6

Там хорошая и умная реализация "нечеткого" словаря в pywinauto - это может быть идеальным для того, что вам нужно здесь.

https://code.google.com/p/pywinauto/source/browse/pywinauto/fuzzydict.py

и docs: http://pywinauto.googlecode.com/hg/pywinauto/docs/code/pywinauto.fuzzydict.html

(отредактируйте: хотя, если вы специально хотите совместить с началом ключа, вам может потребоваться заменить логику SequenceMatcher своим пользовательским кодом)

Ответ 7

Вы можете использовать встроенную функцию фильтрации для фильтрации словарей, списков и т.д. В зависимости от конкретных условий.

filtered_dict = dict(filter(lambda item: "Date" in item[0], my_dict.items()))

Преимущество в том, что вы можете использовать его для разных структур данных.