Python:优化比较两个整数的列表理解

Python:优化比较两个整数的列表理解,python,list-comprehension,Python,List Comprehension,我有一个作用于两个整数列表的列表理解。它的作用类似于itertools.product,带有一个过滤器来丢弃两者相等的元素,并通过比较对它们进行排序 代码如下: to_add = [(min(atom_1, atom_2), max(atom_1, atom_2)) for atom_1 in atoms_1 for atom_2 in atoms_2 if atom_2 != atom_1] add_dict = coll.defaultdict(lis

我有一个作用于两个整数列表的列表理解。它的作用类似于
itertools.product
,带有一个过滤器来丢弃两者相等的元素,并通过比较对它们进行排序

代码如下:

to_add = [(min(atom_1, atom_2), max(atom_1, atom_2))
          for atom_1 in atoms_1 for atom_2 in atoms_2
          if atom_2 != atom_1]
add_dict = coll.defaultdict(list)
for k, v in to_add:
    add_dict[k].append(v)
我在编写时看到的最明显的一点是,不需要先调用
min
,然后再调用
max
。我真正想要的是
min
和另一个,但我想不出如何摆脱对
max
的冗余调用

我分析了它并得到了以下结果,这些结果代表了10次重复(
read\u amber.py
是最重要的函数调用的名称):

62880808函数调用(62880792原语调用)在14.746秒内完成
订购人:内部时间
ncalls tottime percall cumtime percall文件名:lineno(函数)
19 6.786 0.357 10.688 0.563读取琥珀色。py:256(添加除外条款)
16431524 1.625 0.000 1.625 0.000{min}
16431511 1.295 0.000 1.295 0.000{max}
842947 1.051 0.000 1.051 0.000{“str”对象的方法“格式”}
842865 1.031 0.000 1.557 0.000{filter}
16457861 0.838 0.000 0.838 0.000{“列表”对象的“附加”方法}
1 0.793 0.793 3.757 3.757读取琥珀色。py:79(写入)
8414872 0.526 0.000 0.526 0.000读取琥珀色。py:130()
1685897 0.266 0.000 0.266 0.000{“文件”对象的“写入”方法}
97489 0.142 0.000 0.142 0.000{已排序}
1 0.130 0.130 0.300 0.300读取琥珀色。py:32(读取自)
247198 0.127 0.000 0.155 0.000读取琥珀色。py:134(数据转换)
848267/848263 0.042 0.000 0.042 0.000{len}
1 0.038 0.038 0.038 0.038读取琥珀色。py:304(更新排除列表)
500352 0.028 0.000 0.028 0.000{“str”对象的“lower”方法}
有没有办法摆脱一个冗余的
min/max
调用?有没有其他明显的方法可以加速这段代码

我已经尝试过使用
itertools
生成器,但是列表理解速度更快。我还尝试了
排序
和必要的强制转换,但是
min/max
比这更快

最后,我还不熟悉使用
cProfile
。按“tottime”排序是否合理?

那么:

import collections as coll
import itertools

add_dict = coll.defaultdict(list)
for atom_1, atom_2 in itertools.product(atoms_1, atoms_2):
    if atom_1 == atom_2: continue
    (atom_min, atom_max) = (atom_1, atom_2) if atom_1 < atom_2 else (atom_2, atom_1)
    add_dict[atom_min].append(atom_max)

atoms\u 1
atoms\u 2
的格式是什么?只是python列表?numpy lists?是否实际需要添加中间列表
。我不认为这需要使用
numpy
。@AshwiniChaudhary不,不需要,但我认为将其放入其中几乎不会增加任何开销。无论如何,在启动
for
循环时,列表理解将得到充分评估,这是对的吗?嗯
numpy
不是必需的,但是它对长列表进行了一些优化,可以帮助加快速度。对于你的问题,是的,理解力会得到充分的评估。
import collections as coll
import itertools

add_dict = coll.defaultdict(list)
for atom_1, atom_2 in itertools.product(atoms_1, atoms_2):
    if atom_1 == atom_2: continue
    (atom_min, atom_max) = (atom_1, atom_2) if atom_1 < atom_2 else (atom_2, atom_1)
    add_dict[atom_min].append(atom_max)
add_dict = coll.defaultdict(list)
for atom_1, atom_2 in itertools.product(atoms_1, atoms_2):
    if atom_1 == atom_2: continue
    if atom_1 < atom_2:
        add_dict[atom_1].append(atom_2)
    else:
        add_dict[atom_2].append(atom_1)
import collections as coll
import itertools

atoms_1 = [1,2,3,4,5,6]
atoms_2 = [2,4,6,1,2,3]

def old():
    to_add = [(min(atom_1, atom_2), max(atom_1, atom_2)) for atom_1 in atoms_1 for atom_2 in atoms_2 if atom_2 != atom_1]
    add_dict = coll.defaultdict(list)
    for k, v in to_add:
        add_dict[k].append(v)
    return add_dict

def new(): 
    add_dict = coll.defaultdict(list)
    for atom_1, atom_2 in itertools.product(atoms_1, atoms_2):
        if atom_1 == atom_2: continue
        (atom_min, atom_max) = (atom_1, atom_2) if atom_1 < atom_2 else (atom_2, atom_1)
        add_dict[atom_min].append(atom_max)    
    return add_dict

import timeit
print(timeit.timeit("old()", setup="from __main__ import old"))  # 20.76972103
print(timeit.timeit("new()", setup="from __main__ import new"))  # 10.9827100827
atoms_1 = [1,2,3,4,5,6] * 5
atoms_2 = [2,4,6,1,2,3] * 5

print(timeit.timeit("old()", setup="from __main__ import old", number=100000)) # 46.2878425701
print(timeit.timeit("new()", setup="from __main__ import new", number=100000)) # 21.9272824532