Если вы используете dict, то да, вам придется перебирать все ключи, чтобы найти любой, который соответствует.Dicts построены на хеш-таблицах, а хеш-функции не имеют никакого понятия «начинается с» или «закрывается», чтобы использовать их в своих интересах (фактически, они специально разработаны, чтобы давать очень разные выходные данные для близких входов).
Совсем не сложно делать то, что вы хотите:
for k, v in d.items():
if s.startswith(k):
v.append(s)
break
else:
# whatever you want to do if no prefix exists
Но неэффективно, если диктат большой, потому что вы выполняете линейный поиск.
Вы можете сделать его линейным по длине ключа, а не по длине слова (который на самом деле будет медленнее в вашем тестовом примере, но, вероятно, быстрее в большинстве случаев).случаи, когда производительность имеет значение):
for i in range(len(s), 0, -1):
try:
d[k[:i]].append(s)
break
except KeyError:
pass
else:
# whatever you want to do if no prefix exists
Но если вам нужна оптимальная эффективность, вы хотите взглянуть на логарифмическую структуру данных, такую как сбалансированное двоичное дерево поиска, b-дерево, skiplist,три или даже простой старый список, сохраненный в отсортированном порядке.Большинство реализаций таких типов, которые вы можете найти в PyPI или хранилище рецептов ActiveState, имеют метод для поиска места вставки для ключа в отсортированном порядке.Или, если вы используете простой старый список, просто используйте модуль bisect
в stdlib.Просто проверьте ключ перед тем местом вставки, и он либо начинается с вашего ключа, либо ничего не делает.
Например, с sortedcontainers.SortedDict
:
i = d.bisect(s)
if d.iloc[i].startswith(s):
d[d.iloc[i]].append(s)
else:
# whatever you want to do if no prefix exists
Префиксный набор, вероятно, будет наиболее эффективным, если у вас огромный и плотный набор ключей, и вы выполняете много запросов и вставок.Но по другим характеристикам другие могут победить.Так что, если это имеет значение, вы можете попробовать несколько и проверить.