【问题标题】:optimizing python code for performance优化python代码以提高性能
【发布时间】:2012-12-28 01:46:29
【问题描述】:

假设这首歌 i 已经播放了 fi 次,但 Zipf 定律预测它会 已播放zi 次。然后你定义歌曲i的质量为qi = fi/zi .你的软件应该选择qi的最高值的歌曲。

输入的第一行包含两个整数n 和m(1 <= n < 50 000,1 <= m <= n),专辑中歌曲的数量,以及要选择的歌曲数量。然后按照n 行。这些行中的i'th 包含一个整数fi 和字符串si,其中0 <= fi@ 987654340@ 是i'th 歌曲被收听的次数,si 是歌曲的名称。 每首歌曲名称最多包含 30 个字符,并且仅包含字符 a-z、0-9 和下划线 (_)。

输出质量最高的m首歌曲列表qi,按质量降序排列。如果两首歌曲质量相同,则优先考虑专辑中最先出现的那首(大概制作人有理由将那首歌曲放在另一首之前)。

sample input 
4 2
30 one
30 two
15 three
25 four


sample output
four
two

我对 python 很陌生,我正在尝试解决这个难题,我认为我得到了正确的答案,但我必须做得更快,有什么建议吗?

from __future__ import division

def main():
    import sys
    from operator import itemgetter

    data = sys.stdin.readlines()
    line1 = data[0].split(" ")
    numberofselect = line1[1]

    qualitydict = {};
    songdict = {};
    a = 0

    for x in range(1, len(data)):
        item = data[x].split(" ");
        item1 = item[1].split("\n");
        f = float(item[0])
        z = float(1/x)
        qualitydict[item1[0]] = (f/z)
        if ((f/z) in songdict.keys()):
            songdict[(f/z)].append(item1[0])
        else:
            songdict[(f/z)] = [item1[0]]

    items = songdict.items()
    items.sort(key = itemgetter(0), reverse=True)

    for key, value in items:
            for element in value:
                if (a < int(numberofselect)):
                    print element
                    a = a + 1

main();

【问题讨论】:

  • 旁注:取自编程挑战:scrool.se/static/documents/spotify-job-site.pdf
  • 我会鼓励您try this method 找出代码的哪一部分花费的时间最多。
  • 导入 from __future__ import division 后,您无需通过 float 进行投射。执行fz = f/z 并替换所有f/z。
  • 我认为我需要保持浮动,因为我在某个点后会失去精度,因此得到错误的答案

标签: python performance optimization


【解决方案1】:

您可以在可读性和性能方面进行许多改进[未测试]:

from __future__ import division
import sys
from operator import itemgetter
from collections import defaultdict

def main():

    line1 = sys.stdin.readline().split(" ")
    numberofselect = int(line1[1])

    qualitydict = {}
    songdict = defaultdict(list)

    for x, line in enumerate(sys.stdin, start=1):
        tokens = line.split()
        val = float(tokens[0]) * x
        qualitydict[tokens[1]] = val
        songdict[val].append(tokens[1])

    items = songdict.items()
    items.sort(key=itemgetter(0), reverse=True)
    a = 0
    for key, value in items:
            for element in value:
                if a < numberofselect:
                    print element
                    a += 1

main()

特别是:

  • 将defaultdict 用于songdict。如果密钥不存在,它将自动创建一个新的list 值。另外:不要使用key in your_dict.keys() 来查看某个键是否在字典中,因为该检查是O(n)。使用key in your_dict,这需要O(1) 时间。请注意,使用 defaultdict 您根本不需要进行检查,它已经为您完成了。

  • 您将z 定义为1/x,然后您执行f/z,但这与执行f * x 相同,唯一的区别是后者会更精确(x是一个整数,所以1/x 会损失一些精度)。

  • 我想知道是否有必要使用op.itemgetter(0) 对项目进行排序。我的意思是,元素是元组,因此它们将首先按第一个键排序,然后按第二个键排序,结果将是您想要按质量和按字母顺序排序的歌曲(当质量是不止一首歌曲相同)。请注意,即使您可能认为使用op.itemgetter(0) 进行排序会更快,但我认为这不一定是正确的,因为您为每个元素添加了一个函数调用,python 必须使用一些空间来保留键值。

事实上,如果我们检查时间:

>>> timeit.timeit('L.sort()', 'import random;L = [(random.randint(0, 100), i) for i in range(3000)]', number=10000)
1.3252038955688477
>>> timeit.timeit('L.sort(key=operator.itemgetter(0))', 'import random;import operator;L = [(random.randint(0, 100), i) for i in range(3000)]', number=10000)
2.926893949508667

增加大小会提高 itemgetter 版本的性能,但您必须仔细检查它在哪个点变得更好,因为即使使用 50000 元素:

>>> timeit.timeit('L.sort()', 'import random;L = [(random.randint(0, 1000), i) for i in range(50000)]', number=1000)
13.771193027496338
>>> timeit.timeit('L.sort(key=operator.itemgetter(0))', 'import random;import operator;L = [(random.randint(0, 1000), i) for i in range(50000)]', number=1000)
21.419496059417725
  • line.split() 没有在任何空格上拆分参数。

例如:

>>> 'A string with   some    space,\ttabs and \n\n newlines'.split()
['A', 'string', 'with', 'some', 'space,', 'tabs', 'and', 'newlines']

与以下完全不同:

>>> 'A string with   some    space,\ttabs and \n\n newlines'.split(' ')
['A', 'string', 'with', '', '', 'some', '', '', '', 'space,\ttabs', 'and', '\n\n', 'newlines']

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 2021-03-24
    • 2017-10-13
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    相关资源
    最近更新 更多