您想使用itertools.accumulate() iterable 来生成您的长度的累积重量:
from itertools import accumulate
def schedule(jobs_list, sort_key):
sorted_jobs = sorted(jobs_list, key=sort_key, reverse=True)
acc_lengths = accumulate(job[1] for job in sorted_jobs)
weighted_completion_times = (al * job[0] for al, job in zip(acc_lengths, sorted_jobs))
return sum(weighted_completion_times)
请注意,这绝不会构建除排序列表之外的新列表。通过避免构建中间列表以及避免重新汇总越来越长的子列表(使这种 O(N) 与您的 O(N^2) 方法相比),上述方法也更有效;仅在您的短样本上,时间就有 25% 的改进:
>>> from itertools import accumulate
>>> from timeit import timeit
>>> def schedule_lists(jobs_list, sort_key):
... sorted_jobs = sorted(jobs_list, key=sort_key, reverse=True)
... lengths = [job[1] for job in sorted_jobs]
... weighted_completion_times = [sum(lengths[:i + 1]) * sorted_jobs[i][0] for i in range(len(sorted_jobs))]
... return sum(weighted_completion_times)
...
>>> def schedule_acc(jobs_list, sort_key):
... sorted_jobs = sorted(jobs_list, key=sort_key, reverse=True)
... acc_lengths = accumulate(job[1] for job in sorted_jobs)
... weighted_completion_times = (al * job[0] for al, job in zip(acc_lengths, sorted_jobs))
... return sum(weighted_completion_times)
...
>>> jobs = [(99, 1), (100, 3), (100, 3), (99, 2), (99, 2)]
>>> timeit('schedule(jobs, lambda t: (t[0] - t[1], t[0]))',
... 'from __main__ import jobs, schedule_lists as schedule',
... number=100000)
0.6098654230008833
>>> timeit('schedule(jobs, lambda t: (t[0] - t[1], t[0]))',
'from __main__ import jobs, schedule_acc as schedule',
... number=100000)
0.4608557689934969
但是,当您将作业列表大小增加到 1000 时,差异会更加明显:
>>> import random
>>> jobs = [(random.randrange(80, 150), random.randrange(1, 10)) for _ in range(1000)]
>>> timeit('schedule(jobs, lambda t: (t[0] - t[1], t[0]))',
... 'from __main__ import jobs, schedule_lists as schedule',
... number=1000)
5.421368871000595
>>> timeit('schedule(jobs, lambda t: (t[0] - t[1], t[0]))',
... 'from __main__ import jobs, schedule_acc as schedule',
... number=1000)
0.7538741750176996