简体   繁体   English

在Python中明智地串联两个Strings元素列表,而没有嵌套的for循环

[英]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 : 我尝试了使用maplambda的更多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.productmap一起使用:

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那个将不起作用,因为您想要ls1ls2所有元素对,但是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM