2017-04-13 24 views
1

我有一个字符串的两份名单: ls1 = ['a','b','c','d']ls2 = ['k','j','l','m']串联明智的Python字符串元素的两个列表,而嵌套的for循环

我想创建一个第三清单:ls3 = ['a-k','a-j','a-l','a-m','b-k','b-j','b-l','b-m'...'d-m']其中有16个元素。

我可以用下面的嵌套循环for

ls3 = [] 
for elem in ls1: 
    for item in ls2: 
     ls3.append(elem+'-'+item) 

很容易地做到这一点。然而,这是不是很符合Python和揭示了我的C代码的背景。

我尝试一个更Python的解决方案与maplambda

[ map(lambda x,y: x+'-'+y, a,b) for a,b in zip(ls1,ls2) ] 

但我真的不知道我在做什么呢。

什么是Pythonic方式来实现我对嵌套for循环做了什么?

+0

你的嵌套for循环* * Pythonic。 –

回答

3

基准测试脚本你使用的技术完全是Pythonic,直到列表理解被引入到语言中才会是规范的。然而,您建议使用zip的那个将不起作用,因为您需要ls1ls2中的所有元素对,但zip只是使用相应元素而不是所有组合创建对。

如果您想使用更紧凑的代码,那么相应的列表理解是

ls3 = [x+'-'+y for x in ls1 for y in ls2] 

大型列表,或在您需要的性能每盎司(这不应该是你首先要考虑的)看来自@PaulPanzer的解答,他解释了一种更高效但稍微复杂的技术。

3

您可以map一起使用itertools.product

list(map('-'.join, itertools.product('abcd', 'kjlm'))) 
# ['a-k', 'a-j', 'a-l', 'a-m', 'b-k', 'b-j', 'b-l', 'b-m', 'c-k', 'c-j', 'c-l', 'c-m', 'd-k', 'd-j', 'd-l', 'd-m'] 

测试的正确性和时间:

为基准,通常免责声明适用。

在测试条件下,上述(“product map”)解决方案比“天真”列表理解更快(“naive”),但对于小问题大小,边距很小。

大部分的加速似乎是由于避免列表理解。事实上,如果map由列表理解(“product compr”),那么product仍鳞比天真的方法更好,但在小尺寸问题取代落后:

small (4x4) 
results equal: True True 
naive    0.002420 ms 
product compr  0.003211 ms 
product map  0.002146 ms 
large (4x4x4x4x4x4) 
results equal: True True 
naive    0.836124 ms 
product compr  0.681193 ms 
product map  0.385240 ms 

参考

import itertools 
import timeit 

lists = [[chr(97 + 4*i + j) for j in range(4)] for i in range(6)] 

print('small (4x4)') 
print('results equal:', [x+'-'+y for x in lists[0] for y in lists[1]] 
     == 
     list(map('-'.join, itertools.product(lists[0], lists[1]))), end=' ') 
print(['-'.join(t) for t in itertools.product(lists[0], lists[1])] 
     == 
     list(map('-'.join, itertools.product(lists[0], lists[1])))) 

print('{:16s} {:9.6f} ms'.format('naive', timeit.timeit(lambda: [x+'-'+y for x in lists[0] for y in lists[1]], number=1000))) 
print('{:16s} {:9.6f} ms'.format('product compr', timeit.timeit(lambda: ['-'.join(t) for t in itertools.product(lists[0], lists[1])], number=1000))) 
print('{:16s} {:9.6f} ms'.format('product map', timeit.timeit(lambda: list(map('-'.join, itertools.product(lists[0], lists[1]))), number=1000))) 

print('large (4x4x4x4x4x4)') 
print('results equal:', ['-'.join((u, v, w, x, y, z)) for u in lists[0] for v in lists[1] for w in lists[2] for x in lists[3] for y in lists[4] for z in lists[5]] 
     == 
     list(map('-'.join, itertools.product(*lists))), end=' ') 
print(['-'.join(t) for t in itertools.product(*lists)] 
     == 
     list(map('-'.join, itertools.product(*lists)))) 

print('{:16s} {:9.6f} ms'.format('naive', timeit.timeit(lambda: ['-'.join((u, v, w, x, y, z)) for u in lists[0] for v in lists[1] for w in lists[2] for x in lists[3] for y in lists[4] for z in lists[5]], number=1000))) 
print('{:16s} {:9.6f} ms'.format('product compr', timeit.timeit(lambda: ['-'.join(t) for t in itertools.product(*lists)], number=1000))) 
print('{:16s} {:9.6f} ms'.format('product map', timeit.timeit(lambda: list(map('-'.join, itertools.product(*lists))), number=1000))) 
+0

这非常不必要地使用库模块来提供一种解决方案,该解决方案只使用内置语言结构可以更快地工作(尽管它具有回答OP如何避免嵌套循环的问题的优点,但它的成本很高) 。 – holdenweb

+0

我认为@holdenweb是不必要的关键。这个解决方案比列表理解方法更快,明确地表明它生成输入的产品,并且可以容易地推广到任意数量的输入。我认为这两个答案都教授有用的东西 –

+0

啊,适度的声音。谢谢@ mfripp,您的评论是非常受欢迎的。 –

相关问题