如果有这样的列表:
shops=['A','B','C','D']
并且想要创建以下新列表(我将每个元素彼此交叉并创建一个字符串,其中第一部分在第二部分之前是字母数字):
['A-B', 'A-C', 'A-D']
['A-B', 'B-C', 'B-D']
['A-C', 'B-C', 'C-D']
['A-D', 'B-D', 'C-D']
我有这样的事情:
for a in shops:
cons = []
for b in shops:
if a!=b:
con = [a,b]
con = sorted(con, key=lambda x: float(x))
cons.append(con[0]+'-'+con[1])
print(cons)
然而,对于大型列表来说这是非常慢的(例如1000我有1000 * 999 * 0.5输出)。我一直在寻找一种更有效的方法吗?
我可以使用if-else子句进行排序,例如
for a in shops:
cons = []
for b in shops:
if a<b:
cons.append(a+"-"+b)
elif a>b:
cons.append(b+"-"+a)
print(cons)
其中,我还没有定时 - 但是我认为主要的减速是双循环
答案 0 :(得分:9)
您可以使用一些额外的检查来创建嵌套列表理解:
>>> shops=['A','B','C','D']
>>> [["-".join((min(a,b), max(a,b))) for b in shops if b != a] for a in shops]
[['A-B', 'A-C', 'A-D'],
['A-B', 'B-C', 'B-D'],
['A-C', 'B-C', 'C-D'],
['A-D', 'B-D', 'C-D']]
请注意,这可能不会比您的代码快得多,因为您仍然必须生成所有这些组合。在实践中,您可以将其设置为生成器表达式,因此元素不会一次全部生成,而只是“根据需要”生成:
gen = (["-".join((min(a,b), max(a,b))) for b in shops if b != a] for a in shops)
for item in gen:
print(item)
更新:我使用IPython的%timeit
进行了一些时序分析。结果证明你的第二次实施是最快的。使用100个字符串(map(str, range(100))
)的列表进行测试,然后将每个方法转换为生成器。
In [32]: %timeit list(test.f1()) # your first implementation
100 loops, best of 3: 13.5 ms per loop
In [33]: %timeit list(test.f2()) # your second implementation
1000 loops, best of 3: 1.63 ms per loop
In [34]: %timeit list(test.g()) # my implementation
100 loops, best of 3: 3.49 ms per loop
您可以使用简单的if/else
代替min/max
加快速度,就像在第二次实施中一样,它们的速度也相同。
(["-".join((a,b) if a < b else (b,a)) for b in shops if b != a] for a in shops)
答案 1 :(得分:4)
如果列表已排序且没有重复项,您可以在列表中跟踪您的位置,以避免必须进行比较才能获得订单。
from itertools import chain, islice
combos = []
for i, s in enumerate(shops):
combo = ['{0}-{1}'.format(a, b) for a, b in chain(
((c, s) for c in islice(shops, None, i),
((s, c) for c in islice(shops, i+1))]
combos.append(combo)
编辑:更新为使用生成器
答案 2 :(得分:2)
根据你的说法:
我互相交叉每个元素并在第一个字符串中创建一个字符串 部分是在第二个之前的字母数字
您可以使用以下两种组合:
>>> form itertools import combinations
>>> list(combinations(['_'.join(i) for i in combinations(shops,2)],3)
... )
[('A_B', 'A_C', 'A_D'), ('A_B', 'A_C', 'B_C'), ('A_B', 'A_C', 'B_D'), ('A_B', 'A_C', 'C_D'), ('A_B', 'A_D', 'B_C'), ('A_B', 'A_D', 'B_D'), ('A_B', 'A_D', 'C_D'), ('A_B', 'B_C', 'B_D'), ('A_B', 'B_C', 'C_D'), ('A_B', 'B_D', 'C_D'), ('A_C', 'A_D', 'B_C'), ('A_C', 'A_D', 'B_D'), ('A_C', 'A_D', 'C_D'), ('A_C', 'B_C', 'B_D'), ('A_C', 'B_C', 'C_D'), ('A_C', 'B_D', 'C_D'), ('A_D', 'B_C', 'B_D'), ('A_D', 'B_C', 'C_D'), ('A_D', 'B_D', 'C_D'), ('B_C', 'B_D', 'C_D')]
>>>
首先,您可以在列表推导中使用组合来创建有序对,并使用str.join
将它们连接起来。然后使用其他组合来创建三元组。