使用Python在列表中查找字符串匹配计数

时间:2013-06-03 22:50:44

标签: python list search python-3.x

我读了一个文本文件进行分析,每个单词都附加到一个列表中并给出一个id

#!/usr/bin/python3
with fi as myfile:
  for line in myfile:
    for item in line.split(' '):
      db[0].append(id_+1)
      db[2].append(item)
      ...more stuff

然后我通过列表搜索每个单词以查找其匹配项,并将计数存储为 sim1 。如果找到匹配项,我会测试下一个单词是否与连续单词匹配,并将其计数存储为 sim2 。同样适用于 sim3 。我的代码如下:

for i in range(id_-3):
  sim1=0
  sim2=0
  sim3=0
  for j in range(id_-3):
    if i==j:  continue;
    if db[2][i] == db[2][j]:
      sim1 += 1
      if db[2][i+1] == db[2][j+1]:
        sim2 += 1
        if db[2][i+2] == db[2][j+2]:
          sim3 += 1
  db[3].append(sim1)
  db[4].append(sim2)
  db[5].append(sim3)

这样可行,但速度太慢了! 我相信python提供了更快的搜索方法,但我仍然是Py新手!

2 个答案:

答案 0 :(得分:2)

算法的缓慢主要来自于这样一个事实,即你有一个内部循环,它迭代外部循环中包含的len(db [2])次,它也会迭代len(db [2])次。这意味着内部代码正在执行len(db [2])^ 2次。例如,如果您的文件很大并且您正在解析5000个单词,则代码运行5000 ^ 2 = 25,000,000次!

因此,解决问题的攻击角度是找到消除或显着降低内循环成本的方法。下面是一个示例解决方案,只需要遍历len(db [2])一次,然后执行第二个单独的循环,迭代一个更小的项集。在第二次迭代中有一些内部循环,但它们运行的​​次数更少,并且几乎无关紧要。

我使用一个大约48kb的文本文件计算你的算法和我的算法。您的算法在我的计算机上平均大约14秒,我的算法平均为0.6秒。因此,通过取消内部循环,算法现在快了23倍。我还进行了一些其他的小优化,例如将比较更改为数字而不是文本,并从头开始创建完整大小的存储阵列,以避免使用append()。 Append()使解释器根据需要动态增加数组的大小,这比较慢。

from collections import defaultdict

# Create zero-filled sim1, sim2, sim3 arrays to avoid append() overhead
len_ = len(db[2]) - 2
for _ in range(3):
    db.append([0] * len_)

# Create dictionary, containing d['word'] = [count, [indexes]]
# Do just one full iteration, and make good use of it by calculating
# sim1 (as 'count') and storing an array of number indexes for each word,
# allowing for a very efficient loop coming up...
d = defaultdict(lambda: [0, []])
for index, word in enumerate(db[2]):
    if index < len_:
        # Accumulate sim1
        d[word][0] += 1 
    # Store all db[2] indexes where this word exists
    d[word][1].append(index) 

# Now loop only through words which occur more than once (smaller loop)
for word, (count, indexes) in d.iteritems():
    if count > 1:
        # Place the sim1 values into the db[3] array
        for i in indexes:
            if i < len_:
                db[3][i] = count - 1
                # Look for sim2 matches by using index numbers
                next_word = db[2][i+1]
                for next_word_index in d[next_word][1]:
                    if next_word_index - 1 != i and next_word_index - 1 in indexes:
                        # Accumulate sim2 value in db[4]
                        db[4][i] += 1
                        # Look for sim3 matches
                        third_word = db[2][i+2]
                        if third_word == db[2][next_word_index + 1]:
                            # Accumulate sim3 value in db[5]
                            db[5][i] += 1

答案 1 :(得分:-2)

是的,你正在进行字符串比较。那真的很慢。 你想要的是将你的字符串编译为常规模式。 :)

从python中查看库Python: re