最快的方法来确定两个字符串是否在一大串字符串中由一个字母相差

时间:2016-03-24 18:56:29

标签: python python-3.x

我正在尝试比较两个字符串并将其中一个字符串添加到列表中,如果它们几乎相等(由单个字母区分)。什么是最快的方法,因为我的单词超过90k并且这样做通常需要太长时间?

编辑:其中一个词(下面代码中的comparison_word)不会改变。

EDIT2:单词长度必须相等

这是我目前的代码:

    for word in set_of_words:
        amount = 0  
        if len(word) == len(comparison_word):
            for i in range(len(word)):
                if comparison_word[i] != word[i]:
                    amount += 1
            if amount == 1:
                list_of_words.append(word)
    return list_of_words

4 个答案:

答案 0 :(得分:2)

您可能会发现zip比索引更有效:

def almost_equal(set_of_words,comp):
    ln = len(comp)
    for word in set_of_words:
        count = 0
        if len(word) == ln:
            for a, b in zip(word, comp):
                count += a != b
                if count == 2:
                    break
            else:
                yield word

演示:

In [5]: list(almost_equal(["foo","bar","foob","foe"],"foa"))
Out[5]: ['foo', 'foe']

答案 1 :(得分:1)

我们的想法是减少正在完成的工作量:

n_comparison_word = len(comparison_word)
for word in set_of_words:
    amount = 0
    n_word = len(word)
    if n_word != n_comparison_word:
        continue
    for i in range(n_word):
        if comparison_word[i] != word[i]:
            amount += 1
        if amount == 2:
            break
    if amount == 1:
        list_of_words.append(word)
return list_of_words

一些注意事项:

  • len(comparison_word)的值只需计算一次(永远)。
  • len(word)的值需要计算一次(每次迭代循环)。
  • 您知道当amount达到值2时,您可以停止查看单词(或更多 - 在任何情况下,该单词都不能再成为结果的一部分。)

关于代码中使用的continuebreak语句,可能值得阅读this part of the Python documentation

答案 2 :(得分:1)

以下在约25毫秒内搜索我的61K字词典。

import re

def search(word, text):
    ws = [r'\b{}[^{}]{}\b'.format(w[:i],w[i],w[i+1:]) for i in range(len(word))]

    for mo in re.finditer('|'.join(ws), text):
        yield mo.group()

with open("/12dicts/5desk.txt") as f:
    text = f.read()

for hit in search('zealoos', text):
    print(hit)                         #prints zealous

假设字符串列表在一个文件中,每行一个字符串,将其作为一个长字符串读取,并使用正则表达式在字符串中搜索匹配项。

search()会说“'什么'并把它变成这样的正则表达式:

\b[^w]hat\b|\bw[^h]at\b|\bwh[^a]t\b|\bwha[^t]\b

然后扫描所有单词并找到所有近乎未命中 - 以C-speed。

答案 3 :(得分:0)

Haven没有进行详尽的测试,但如果comparison_word不是太长(少于6个字母),并且您的set_of_words可以更改,那么计算所有可接受的内容可能是值得的单词,将它们存储在一个集合中,只需遍历set_of_words并测试word in acceptable_words

如果没有,请点击我的代码:

for word in set_of_words:
  different_letter_exists = False
  length = len(word)
  if length == len(comparison_word):
    for i, letter in enumerate(word):
        if letter != comparison_word[i]:
            if different_letter_exists:
                break
            else:
                different_letter_exists = True
    if i == length:
        list_of_words.append(word)

基本上:对于每个单词,一旦遇到不同的字母,different_letter_exists将设置为True。如果你再次遇到它,你就会脱离循环。只有i == length才会添加一个新单词,只有当enumerate一直到达结尾时才会发生这种情况,只有当只有一个不同的字母存在时才会发生。

祝你好运:)