大多数pythonic方式交错两个string

将两个string网格化在一起最麻烦的方法是什么?

例如:

input:

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = 'abcdefghijklmnopqrstuvwxyz' 

输出:

 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

对我来说,最pythonic *方法是几乎相同的事情,但使用+运算符连接每个string中的单个字符:

 res = "".join(i + j for i, j in zip(u, l)) print(res) # 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

它也比使用两个join()调用更快:

 In [5]: l1 = 'A' * 1000000; l2 = 'a' * 1000000 In [6]: %timeit "".join("".join(item) for item in zip(l1, l2)) 1 loops, best of 3: 442 ms per loop In [7]: %timeit "".join(i + j for i, j in zip(l1, l2)) 1 loops, best of 3: 360 ms per loop 

存在更快的方法,但它们经常混淆代码。

注意:如果两个inputstring的长度一样,那么较长的string将被截断,因为zip停止在较短string的末尾迭代。 在这种情况下,应该使用itertools模块中的zip_longest (Python 2中的izip_longest )来代替zip以确保两个string都完全耗尽。


*从Python的禅宗引用: 可读性计数
Pythonic = 可读性 ; i + j只是在视觉上更容易parsing,至less在我眼中。

更快的select

其他方式:

 res = [''] * len(u) * 2 res[::2] = u res[1::2] = l print(''.join(res)) 

输出:

 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

速度

看起来更快:

 %%timeit res = [''] * len(u) * 2 res[::2] = u res[1::2] = l ''.join(res) 100000 loops, best of 3: 4.75 µs per loop 

比迄今为止最快的解决scheme:

 %timeit "".join(list(chain.from_iterable(zip(u, l)))) 100000 loops, best of 3: 6.52 µs per loop 

对于更大的string:

 l1 = 'A' * 1000000; l2 = 'a' * 1000000 %timeit "".join(list(chain.from_iterable(zip(l1, l2)))) 1 loops, best of 3: 151 ms per loop %%timeit res = [''] * len(l1) * 2 res[::2] = l1 res[1::2] = l2 ''.join(res) 10 loops, best of 3: 92 ms per loop 

Python 3.5.1。

不同长度的string的变化

 u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = 'abcdefghijkl' 

较短的一个决定长度(相当于zip()

 min_len = min(len(u), len(l)) res = [''] * min_len * 2 res[::2] = u[:min_len] res[1::2] = l[:min_len] print(''.join(res)) 

输出:

 AaBbCcDdEeFfGgHhIiJjKkLl 

更长的一个决定长度( itertools.zip_longest(fillvalue='')等效)

 min_len = min(len(u), len(l)) res = [''] * min_len * 2 res[::2] = u[:min_len] res[1::2] = l[:min_len] res += u[min_len:] + l[min_len:] print(''.join(res)) 

输出:

 AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ 

join()zip()

 >>> ''.join(''.join(item) for item in zip(u,l)) 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

在Python 2中, 到目前为止 ,做事情的速度更快,大约3倍的小string的列表切片的速度和长的约30倍的速度是

 res = bytearray(len(u) * 2) res[::2] = u res[1::2] = l str(res) 

虽然这在Python 3上不起作用。 你可以实现类似的东西

 res = bytearray(len(u) * 2) res[::2] = u.encode("ascii") res[1::2] = l.encode("ascii") res.decode("ascii") 

但是到那时你已经在小string的列表切片上失去了收益(它仍然是长string速度的20倍),这对于非ASCII字符还是不起作用的。

FWIW,如果你在大量的string上进行这样的操作,并且需要每个周期, 并且出于某种原因必须使用Pythonstring…下面是如何做到这一点:

 res = bytearray(len(u) * 4 * 2) u_utf32 = u.encode("utf_32_be") res[0::8] = u_utf32[0::4] res[1::8] = u_utf32[1::4] res[2::8] = u_utf32[2::4] res[3::8] = u_utf32[3::4] l_utf32 = l.encode("utf_32_be") res[4::8] = l_utf32[0::4] res[5::8] = l_utf32[1::4] res[6::8] = l_utf32[2::4] res[7::8] = l_utf32[3::4] res.decode("utf_32_be") 

小型的常见情况也会有所帮助。 FWIW,对于小string来说,这只是列表切片速度的3倍,对于小string来说,速度却只有4到5倍。

无论哪种方式,我更喜欢join解决scheme,但由于时间在其他地方提到,所以我想我也可以join。

如果你想最快的方法,你可以结合itertools与operator.add

 In [36]: from operator import add In [37]: from itertools import starmap, izip In [38]: timeit "".join([i + j for i, j in uzip(l1, l2)]) 1 loops, best of 3: 142 ms per loop In [39]: timeit "".join(starmap(add, izip(l1,l2))) 1 loops, best of 3: 117 ms per loop In [40]: timeit "".join(["".join(item) for item in zip(l1, l2)]) 1 loops, best of 3: 196 ms per loop In [41]: "".join(starmap(add, izip(l1,l2))) == "".join([i + j for i, j in izip(l1, l2)]) == "".join(["".join(item) for item in izip(l1, l2)]) Out[42]: True 

但是将izipchain.from_iterable结合起来会更快

 In [2]: from itertools import chain, izip In [3]: timeit "".join(chain.from_iterable(izip(l1, l2))) 10 loops, best of 3: 98.7 ms per loop 

chain(*chain.from_iterable(...之间也有很大的区别。

 In [5]: timeit "".join(chain(*izip(l1, l2))) 1 loops, best of 3: 212 ms per loop 

有没有这样的事情作为一个发电机join,传递一个总是会慢,因为python将首先build立一个列表使用的内容,因为它做了两遍数据,一个找出所需的大小,一个实际上使用生成器不可能的连接:

join.h :

  /* Here is the general case. Do a pre-pass to figure out the total * amount of space we'll need (sz), and see whether all arguments are * bytes-like. */ 

另外如果你有不同的长度string,你不想丢失数据,你可以使用izip_longest :

 In [22]: from itertools import izip_longest In [23]: a,b = "hlo","elworld" In [24]: "".join(chain.from_iterable(izip_longest(a, b,fillvalue=""))) Out[24]: 'helloworld' 

对于Python 3,它被称为zip_longest

但是对于python2,veedrac的build议是迄今为止最快的:

 In [18]: %%timeit res = bytearray(len(u) * 2) res[::2] = u res[1::2] = l str(res) ....: 100 loops, best of 3: 2.68 ms per loop 

你也可以使用mapoperator.add来做到这一点:

 from operator import add u = 'AAAAA' l = 'aaaaa' s = "".join(map(add, u, l)) 

输出

 'AaAaAaAaAa' 

这个映射是从第一个可迭代的u和第二个可迭代的l的第一个元素开始的,并应用作为第一个参数add提供的函数。 然后join只是join他们。

很多这些build议都假定string长度相等。 也许这涵盖了所有合理的用例,但至less在我看来,你似乎也想要容纳不同长度的string。 或者我是唯一一个认为网格应该有点像这样工作的人:

 u = "foobar" l = "baz" mesh(u,l) = "fboaozbar" 

其中一种方法是:

 def mesh(a,b): minlen = min(len(a),len(b)) return "".join(["".join(x+y for x,y in zip(a,b)),a[minlen:],b[minlen:]]) 

吉姆的回答非常好,但是这里是我最喜欢的select,如果你不介意几个import:

 from functools import reduce from operator import add reduce(add, map(add, u, l)) 

我喜欢使用两个s,variables名称可以提示/提醒发生了什么事情:

 "".join(char for pair in zip(u,l) for char in pair) 

只是增加另一个更基本的方法:

 st = "" for char in u: st = "{0}{1}{2}".format( st, char, l[ u.index( char ) ] ) 

比当前领先的解决scheme可能更快,更短:

 from itertools import chain u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = 'abcdefghijklmnopqrstuvwxyz' res = "".join(chain(*zip(u, l))) 

速度策略是尽可能地在C级做尽可能多的事情。 相同的zip_longest()修复了不均匀的string,它会和chain()一样从同一个模块中出来,所以不能在这里给我太多点!

我一路上想到的其他解决scheme:

 res = "".join(u[x] + l[x] for x in range(len(u))) res = "".join(k + l[i] for i, k in enumerate(u)) 

感觉有点不pythonic在这里不考虑双列表理解的答案,以O(1)努力处理nstring:

 "".join(c for cs in itertools.zip_longest(*all_strings) for c in cs) 

其中all_strings是您要交错的string的列表。 在你的情况下, all_strings = [u, l] 。 完整的使用示例如下所示:

 import itertools a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' b = 'abcdefghijklmnopqrstuvwxyz' all_strings = [a,b] interleaved = "".join(c for cs in itertools.zip_longest(*all_strings) for c in cs) print(interleaved) # 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

像许多答案一样,最快? 可能不是,但简单而灵活。 另外,没有太多额外的复杂性,这比接受的答案稍微快一些(一般来说,string添加在Python中有点慢):

 In [7]: l1 = 'A' * 1000000; l2 = 'a' * 1000000; In [8]: %timeit "".join(a + b for i, j in zip(l1, l2)) 1 loops, best of 3: 227 ms per loop In [9]: %timeit "".join(c for cs in zip(*(l1, l2)) for c in cs) 1 loops, best of 3: 198 ms per loop 

你可以使用iteration_utilities.roundrobin 1

 u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = 'abcdefghijklmnopqrstuvwxyz' from iteration_utilities import roundrobin ''.join(roundrobin(u, l)) # returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

或同一个包中的ManyIterables类:

 from iteration_utilities import ManyIterables ManyIterables(u, l).roundrobin().as_string() # returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz' 

1这是来自我写的第三方库: iteration_utilities

我会使用zip()来获得一个可读和简单的方法:

 result = '' for cha, chb in zip(u, l): result += '%s%s' % (cha, chb) print result # 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'