самый быстрый способ сравнить строки в Python

Я пишу сценарий в Python, который позволит пользователю вводить строку, которая будет командой, которая дает сценарию команду выполнять определенное действие. Ради аргумента я скажу, что мой список команд:

lock
read
write
request
log

Теперь, я хочу, чтобы пользователь был в состоянии ввести слово "журнал", и это выполнит определенное действие, которое очень просто. Однако я хотел бы распознать частичные слова. Так, например, если пользователь вводит "lo", он должен соответствовать "блокировке", поскольку это выше в списке. Я попытался использовать strncmp от libc, использующего ctypes, чтобы выполнить это, но иметь все же для понимания его.

8
задан Mike Trpcic 13 January 2010 в 02:11
поделиться

10 ответов

Если вы принимаете вклад от пользователя, то почему вы беспокоитесь о скорости сравнения? Даже самая медленная техника будет гораздо быстрее, чем пользователь может воспринимать. Используйте самый простой наиболее понятный код, который вы можете, и оставить эффективность концерн для жестких внутренних петлей.

cmds = [
    "lock",
    "read",
    "write",
    "request",
    "log",
    ]

def match_cmd(s):
    matched = [c for c in cmds if c.startswith(s)]
    if matched:
        return matched[0]
16
ответ дан 5 December 2019 в 05:45
поделиться

Это сделает то, что вы хотите:

def select_command(commands, user_input):
    user_input = user_input.strip().lower()
    for command in commands:
        if command.startswith(user_input):
            return command
    return None

Тем не менее:

Вы кажусь оборажены по неправильной вещи. Так что 50 пользователей означают 50 миллисекунд - вы не будете уходить из города за такую ​​«отставание». Беспокойство о неэффективном доступе к базе данных или проблемы, вызванные пользователями, набрав «R» и получают «чтение», когда они думали, что они получили «запрос». Минимизация нажатий пользователей на риск ошибок настолько 1960-х годов, что это не смешно. Что они используют? ASR33 Телетапы? По крайней мере, вы могли настаивать на уникальном матче - «REA» для чтения и «REQ» для запроса.

5
ответ дан 5 December 2019 в 05:45
поделиться

Jaro_Winkler () в Python-levenshtein может быть то, что вы ищете.

1
ответ дан 5 December 2019 в 05:45
поделиться
-

Это оптимизировано при выполнении времени, как вы запрашивали ... (хотя, скорее всего, не нужно)

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

Итак, вы запускаете это, когда вы начнете свой сервис, а затем у вас на 100% оптимизированные поиски. Я уверен, что есть более умный способ сделать это, так что не стесняйтесь редактировать.

commands = {
  'log': log_function,
  'exit': exit_function,
  'foo': foo_function,
  'line': line_function,
  }

cmap = {}
kill = set()
for command in commands:
  for pos in range(len(1,command)):
    subcommand = command[0:pos]
    if subcommand in cmap:
      kill.add(subcommand)
      del(cmap[subcommand])
    if subcommand not in kill:
      cmap[subcommand] = commands[command]

#cmap now is the following - notice the duplicate prefixes removed?
{
  'lo': log_function,
  'log': log_function,
  'e': exit_function,
  'ex': exit_function,
  'exi': exit_function,
  'exit': exit_function,
  'f' : foo_function,
  'fo' : foo_function,
  'foo' : foo_function,
  'li' : line_function,
  'lin' : line_function,
  'line' : line_function,
}
3
ответ дан 5 December 2019 в 05:45
поделиться

Это адаптировано из реализации TRIE в Python в Python , что вы могли бы сравнить и / или повторно адаптироваться любыми дополнительными функциями, которые вам нужны. Смотрите также в вход в Википедию на попытках .

class Trie:
    def __init__(self):
        self.root = [None, {}]

    def add(self, key):
        curr_node = self.root
        for ch in key:
            curr_node = curr_node[1].setdefault(ch, [key, {}])
        curr_node[0] = key

    def find(self, key):
        curr_node = self.root
        for ch in key:
            try:
                curr_node = curr_node[1][ch]
            except KeyError:
                return None
        return curr_node[0]

Настройка (порядок добавления вопросов!):

t = Trie()
for word in [
   'lock',
   'read',
   'write',
   'request',
   'log']:
   t.add(word)

Тогда звоните следующим образом:

>>> t.find('lo')
'lock'
>>> t.find('log')
'log'
>>> t.find('req')
'request'
>>> t.find('requiem')
>>>
0
ответ дан 5 December 2019 в 05:45
поделиться
import timeit

cmds = []
for i in range(1,10000):
    cmds.append("test")

def get_cmds(user_input):
    return [c for c in cmds if c.startswith(user_input)]

if __name__=='__main__':
    t = timeit.Timer("get_cmds('te')", "from __main__ import get_cmds")
    print "%0.3f seconds" % (t.timeit(number=1))

#>>> 0.008 seconds

Итак, в основном, согласно моему комментарию, вы спрашиваете, как оптимизировать операцию, не требующую измеряемого времени или процессора. Я использовал здесь 10,000 команд, и тестовая строка соответствует каждой только для того, чтобы показать, что даже в экстремальных условиях это могут делать сотни пользователей, и они никогда не увидят никакого запаздывания.

0
ответ дан 5 December 2019 в 05:45
поделиться

Я предлагаю вам взглянуть на использование библиотеки питонов для чтения, а не изобретать колесо заново. Пользователю придется нажимать клавишу табуляции для завершения слова, но вы можете настроить readline таким образом, чтобы табуляция по возможности совпадала или циклически перебирала все слова, начинающиеся с текущего корешка.

Похоже, это довольно приличное введение в readline на питонском http://www.doughellmann.com/PyMOTW/readline/index.html

2
ответ дан 5 December 2019 в 05:45
поделиться

Замените на вашу любимую функцию сравнения строк. Довольно быстро, и к делу.

matches = ( x for x in list if x[:len(stringToSearchFor)] == stringToSearchFor )
print matches[0]
0
ответ дан 5 December 2019 в 05:45
поделиться

можно использовать startwith

eg

myword = "lock"
if myword.startswith("lo"):
   print "ok"

или если Вы хотите найти "lo" в слове, независимо от позиции, просто используйте оператор "in"

if "lo" in myword

поэтому, один из способов сделать это:

for cmd in ["lock","read","write","request","log"]:
    if cmd.startswith(userinput):
        print cmd
        break
2
ответ дан 5 December 2019 в 05:45
поделиться

Если я правильно понимаю ваш Q, вы хотите, чтобы фрагмент, который вернет ответ, как только он имеет его, не пройдя дальше через вашу «Список команд». Это должно делать то, что вы хотите:

from itertools import ifilter

def check_input(some_string, code_book) :
    for q in ifilter(code_book.__contains__, some_string) :
        return True
    return False
0
ответ дан 5 December 2019 в 05:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: