问题：插入两个字符串的最pythonic方式

``````u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
``````

``'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'``

What’s the most pythonic way to mesh two strings together?

For example:

Input:

``````u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
``````

Output:

``````'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
``````

回答 0

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

``````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
``````

*引用Python之禅可读性很重要
Pythonic = 对我而言可读性`i + j`至少对于我的眼睛来说，更容易从视觉上进行解析。

For me, the most pythonic* way is the following which pretty much does the same thing but uses the `+` operator for concatenating the individual characters in each string:

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

It is also faster than using two `join()` calls:

``````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
``````

Faster approaches exist, but they often obfuscate the code.

Note: If the two input strings are not the same length then the longer one will be truncated as stops iterating at the end of the shorter string. In this case instead of `zip` one should use `zip_longest` (`izip_longest` in Python 2) from the `itertools` module to ensure that both strings are fully exhausted.

*To take a quote from the Zen of Python: Readability counts.
Pythonic = readability for me; `i + j` is just visually parsed more easily, at least for my eyes.

更快的选择

``````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``````

``````%timeit "".join(list(chain.from_iterable(zip(u, l))))

100000 loops, best of 3: 6.52 µs per loop``````

``````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。

不同长度字符串的变化

``````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``

Faster Alternative

Another way:

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

Output:

``````'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
``````

Speed

Looks like it is faster:

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

100000 loops, best of 3: 4.75 µs per loop
``````

than the fastest solution so far:

``````%timeit "".join(list(chain.from_iterable(zip(u, l))))

100000 loops, best of 3: 6.52 µs per loop
``````

Also for the larger strings:

``````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.

Variation for strings with different lengths

``````u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijkl'
``````

Shorter one determines length (`zip()` equivalent)

``````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))
``````

Output:

``````AaBbCcDdEeFfGgHhIiJjKkLl
``````

Longer one determines length (`itertools.zip_longest(fillvalue='')` equivalent)

``````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))
``````

Output:

``````AaBbCcDdEeFfGgHhIiJjKkLlMNOPQRSTUVWXYZ
``````

回答 2

`join()``zip()`

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

With `join()` and `zip()`.

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

回答 3

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

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

FWIW，如果您在大量字符串上执行此操作并且需要每个周期，并且由于某种原因必须使用Python字符串…以下是操作方法：

``````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")``````

On Python 2, by far the faster way to do things, at ~3x the speed of list slicing for small strings and ~30x for long ones, is

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

This wouldn’t work on Python 3, though. You could implement something like

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

but by then you’ve already lost the gains over list slicing for small strings (it’s still 20x the speed for long strings) and this doesn’t even work for non-ASCII characters yet.

FWIW, if you are doing this on massive strings and need every cycle, and for some reason have to use Python strings… here’s how to do it:

``````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")
``````

Special-casing the common case of smaller types will help too. FWIW, this is only 3x the speed of list slicing for long strings and a factor of 4 to 5 slower for small strings.

Either way I prefer the `join` solutions, but since timings were mentioned elsewhere I thought I might as well join in.

回答 4

``````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

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``````

``````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``````

`````` /* 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.
*/``````

``````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'``````

``````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``````

If you want the fastest way, you can combine itertools with `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

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
``````

But combining `izip` and `chain.from_iterable` is faster again

``````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
``````

There is also a substantial difference between `chain(*` and `chain.from_iterable(...`.

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

There is no such thing as a generator with join, passing one is always going to be slower as python will first build a list using the content because it does two passes over the data, one to figure out the size needed and one to actually do the join which would not be possible using a generator:

`````` /* 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.
*/
``````

Also if you have different length strings and you don’t want to lose data you can use 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'
``````

For python 3 it is called `zip_longest`

But for python2, veedrac’s suggestion is by far the fastest:

``````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
``````

回答 5

``````from operator import add

u = 'AAAAA'
l = 'aaaaa'

``'AaAaAaAaAa'``

map的作用是，它从第一个可迭代对象获取每个元素，`u`并从第二个可迭代对象获取第一个元素，`l`并应用作为第一个参数提供的函数`add`。然后加入只是加入他们。

You could also do this using `map` and `operator.add`:

``````from operator import add

u = 'AAAAA'
l = 'aaaaa'

``````

Output:

``````'AaAaAaAaAa'
``````

What map does is it takes every element from the first iterable `u` and the first elements from the second iterable `l` and applies the function supplied as the first argument `add`. Then join just joins them.

回答 6

``````from functools import reduce

Jim’s answer is great, but here’s my favorite option, if you don’t mind a couple of imports:

``````from functools import reduce

``````

回答 7

``````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:]])``````

A lot of these suggestions assume the strings are of equal length. Maybe that covers all reasonable use cases, but at least to me it seems that you might want to accomodate strings of differing lengths too. Or am I the only one thinking the mesh should work a bit like this:

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

One way to do this would be the following:

``````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:]])
``````

回答 8

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

I like using two `for`s, the variable names can give a hint/reminder to what is going on:

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

回答 9

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

Just to add another, more basic approach:

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

回答 10

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

`all_strings`您要插入的字符串的列表在哪里。就您而言，`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)

``````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``````

Feels a bit un-pythonic not to consider the double-list-comprehension answer here, to handle n string with O(1) effort:

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

where `all_strings` is a list of the strings you want to interleave. In your case, `all_strings = [u, l]`. A full use example would look like this:

``````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)
``````

Like many answers, fastest? Probably not, but simple and flexible. Also, without too much added complexity, this is slightly faster than the accepted answer (in general, string addition is a bit slow in 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
``````

回答 11

``````from itertools import chain

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

res = "".join(chain(*zip(u, l)))``````

``````res = "".join(u[x] + l[x] for x in range(len(u)))

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

Potentially faster and shorter than the current leading solution:

``````from itertools import chain

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

res = "".join(chain(*zip(u, l)))
``````

Strategy speed-wise is to do as much at the C-level as possible. Same zip_longest() fix for uneven strings and it would be coming out of the same module as chain() so can’t ding me too many points there!

Other solutions I came up with along the way:

``````res = "".join(u[x] + l[x] for x in range(len(u)))

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

回答 12

``````u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

from iteration_utilities import roundrobin
''.join(roundrobin(u, l))

`ManyIterables`同一包中的类：

``````from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()

1这来自我编写的第三方库`iteration_utilities`

You could use `iteration_utilities.roundrobin`1

``````u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

from iteration_utilities import roundrobin
''.join(roundrobin(u, l))
``````

or the `ManyIterables` class from the same package:

``````from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()
``````

1 This is from a third-party library I have written: `iteration_utilities`.

回答 13

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

print result
``````result = ''