【问题标题】:Reducing the run time of a loop and increasing its efficiency减少循环的运行时间并提高其效率
【发布时间】:2017-04-21 16:24:47
【问题描述】:

我有一个循环,它需要大量的单词,将每个单词分解成字母并将它们附加到一个大列表中。

然后我检查出现次数最多的字母,如果它还没有出现在字符串中,我会将它存储在一个有两个空格的列表中:

list[0] = 出现次数最多的字母

list[1] = 发生了多少次

这个循环非常低效。它可以工作,但返回值大约需要 25-30 秒。在此之前它会继续运行并且不会返回任何值。

如何提高我编写的代码的效率?

def choose_letter(words, pattern):
    list_of_letters = []
    first_letter = []  # first spot is the letter, second is how many times it appears
    second_letter =[]  # first spot is letter, second how many times it appears
    max_appearances = ["letter", 0]
    for i in range(len(words)):  # splits up every word into letters
        list_of_letters.append(list(words[i]))
    list_of_letters = sum(list_of_letters, [])   # concatenates the lists within the list
    first_letter = list_of_letters.count(0)
    for j in list_of_letters:
        second_letter = list_of_letters.count(j)
        if second_letter >= max_appearances[1] and j not in pattern:
            max_appearances[0] = j
            max_appearances[1] = second_letter
        else:
            list_of_letters.remove(j)
    return max_appearances[0]

【问题讨论】:

  • 这可能更适合codereview.stackexchange.com
  • 当您转到 codereview 时,他们会要求查看您针对此代码运行的分析器的输出。
  • 看起来像是 collections.Counter 的工作。
  • 无论你做什么,我相信你会从使用字典而不是列表来存储你的计数中获益良多。所以dictdefaultdict或上面提到的collections.Counter

标签: python performance loops processing-efficiency


【解决方案1】:

您正在执行大量不需要的循环和操作列表。每次您执行countnot in 时,您都在强制您的程序循环遍历列表/字符串以查找您要查找的内容。从列表中删除所有这些项目也非常昂贵。一个更优雅的解决方案是只循环一次您的单词/字母列表,然后使用字典来计算每个字母的出现次数。从那里,您有一个包含字符/计数对的字典,您可以从那里获取键/值,对列表进行排序并查看前两个值。

from collections import defaultdict
from itertools import chain

def choose_letter(words, pattern=""):
    count_dict = defaultdict(int) # all unknown values default to 0
    for c in chain(*words):
        count_dict[c] += 1
    # you could replace this "not in" with something more efficient
    filtered = [(char, count) for (char,count) in count_dict.items() if char not in pattern] 
    filtered.sort(lambda a,b: -cmp(a[0], b[0]))
    print filtered
    return filtered[0][0]

如果您不想深入研究参数解包、itertools 和 defaultdicts,您可以说:

count_dict = {}
for word in words:
    for char in word:
        count_dict[char] = count_dict.get(char, 0) + 1

...如果您还不想尝试深入研究参数解包。

【讨论】:

    【解决方案2】:

    加快速度的一种方法是选择更好的数据结构。这是一个使用collections.Counter的例子:

    from collections import Counter
    
    def choose_letter(words, pattern):
        pattern = set(pattern)
        letters = (letter
                   for word in words
                   for letter in word
                   if letter not in pattern)
        letters = Counter(letters)
        return letters.most_common(1)[0][0]
    
    
    mywords = 'a man a plan a canal panama'.split()
    vowels = 'aeiou'
    assert choose_letter(mywords, vowels) == 'n'
    

    这是一个使用collections.defaultdict的:

    from collections import defaultdict
    
    def choose_letter(words, pattern):
        pattern = set(pattern)
        counts = defaultdict(int)
        for word in words:
            for letter in word:
                if letter not in pattern:
                    counts[letter] += 1
        return max(counts, key=counts.get)
    
    mywords = 'a man a plan a canal panama'.split()
    vowels = 'aeiou'
    assert choose_letter(mywords, vowels) == 'n'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      • 1970-01-01
      • 2019-10-07
      • 1970-01-01
      • 2016-01-18
      • 2021-08-21
      • 2019-11-06
      相关资源
      最近更新 更多