[英]Concatenating two lists of Strings element wise in Python without Nested for loops
I have two lists of strings: ls1 = ['a','b','c','d']
and ls2 = ['k','j','l','m']
我有两个字符串列表:
ls1 = ['a','b','c','d']
和ls2 = ['k','j','l','m']
I want to create a 3rd list: ls3 = ['a-k','a-j','a-l','a-m','b-k','b-j','b-l','b-m'...'d-m']
which has 16 elements. 我想创建第三个列表:
ls3 = ['a-k','a-j','a-l','a-m','b-k','b-j','b-l','b-m'...'d-m']
,其中包含16个元素。
I can achieve this quite easily with the following nested for
loops 我可以使用以下嵌套的
for
循环轻松实现此目的
ls3 = []
for elem in ls1:
for item in ls2:
ls3.append(elem+'-'+item)
However, this isn't very Pythonic and reveals my C-code background. 但是,这不是Python语言,它揭示了我的C代码背景。
I attempted a more Pythonic solution with map
and lambda
: 我尝试了使用
map
和lambda
的更多Pythonic解决方案:
[ map(lambda x,y: x+'-'+y, a,b) for a,b in zip(ls1,ls2) ]
But I don't really know what I'm doing yet. 但是我真的不知道我在做什么。
What is a Pythonic way to achieve what I've done with my nested for
loops? 用Python的方式可以实现嵌套
for
循环的目的是什么?
You can use itertools.product
together with map
: 您可以将
itertools.product
与map
一起使用:
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']
Test for correctness and timings: 测试正确性和时机:
The usual disclaimers for benchmarks apply. 适用于基准的通常免责声明。
Under the test conditions the above (" product map
") solution is faster than the "naive" list comprehension (" naive
"), although the margin is small for small problem size. 在测试条件下,上述解决方案(“
product map
”)的解决方案比“纯朴的”列表理解(“ naive
”)解决方案要快,尽管对于小问题大小而言,裕度很小。
Much of the speed-up appears to be due to avoiding a list comprehension. 提速的大部分似乎是由于避免了列表理解。 Indeed if
map
is replaced by a list comprehension (" product compr
") then product
still scales better than the naive approach, but at small problem size falls behind: 事实上,如果
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
Benchmark script for reference 基准脚本供参考
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)))
The technique you have used is perfectly Pythonic, and until list comprehensions were introduced into the language would have been canonical. 您所使用的技术完全是Python风格的,并且直到将列表理解引入该语言之前,都是规范的。 The one you suggest using
zip
, however, won't work, because you want all pairs of elements from ls1
and ls2
, but zip
simply creates pairs using the corresponding elements rather than all combinations. 但是,您建议使用
zip
那个将不起作用,因为您想要ls1
和ls2
所有元素对,但是zip
只是使用对应的元素而不是所有组合来创建对。
If you'd like to use more compact code then the appropriate list comprehension would be 如果您想使用更紧凑的代码,则可以使用适当的列表理解
ls3 = [x+'-'+y for x in ls1 for y in ls2]
For large lists, or where you need every ounce of performance (which should never be your first consideration) see the answer from @PaulPanzer, who explains a more efficient though slightly more complex technique. 对于大型列表,或需要任何性能表现的地方(这永远不是您的首要考虑),请参阅@PaulPanzer的答案,他解释了一种更高效但稍微复杂的技术。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.