大多数pythonic方式交错两个字符串

时间:2016-01-13 00:06:53

标签: python string python-2.7 python-3.x

将两个字符串拼接在一起的最pythonic方法是什么?

例如:

输入:

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

输出:

'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

14 个答案:

答案 0 :(得分:126)

对我来说,最pythonic *方式是几乎做同样的事情,但是使用+运算符来连接每个字符串中的各个字符:

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

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

注意:如果两个输入字符串长度相同,那么较长的字符串将被截断,因为 zip 会停止在较短的字符串的末尾迭代。在这种情况下,应该使用zip_longest模块中的 izip_longest (Python 2中的 itertools )代替zip确保两个字符串完全耗尽。

*从 the Zen of Python 中获取引用:可读性计数
对我来说,Pythonic = 可读性; i + j只是在视觉上更容易解析,至少在我看来是这样。

答案 1 :(得分:62)

更快的替代方案

另一种方式:

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

答案 2 :(得分:47)

使用var obj = [{ Primary: "Hejrwe", TestVal: "234723", TestTool: [{ label: 'xyz', num: '23' }, { label: "", num: "" }, { label: "", num: "" }], TestItv: [{ label: 'xyz', num: '23' }, { label: "", num: "" }, { label: "", num: "" }] }, { Primary: "Urwhe", TestVal: "32432", TestTool: [{ label: 'abc', num: '24' }, { label: "", num: "" }, { label: "", num: "" }], TestItv: [{ label: 'abc', num: '24' }, { label: "", num: "" }, { label: "", num: "" }] }]; Object.keys(obj).map(function(index) { var val = obj[index].TestTool; var temp = []; for (var i in val) { if (val[i].label == "") { delete val[i].label; } if (val[i].num == "") { delete val[i].num; } } }); console.log(obj); join()

zip()

答案 3 :(得分:18)

在Python 2上,通过 far 更快的方式做事,大约是小字符串列表切片速度的3倍,长字符串大约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")

但到那时你已经失去了对小字符串列表切片的收益(它仍然是长字符串速度的20倍),这甚至不适用于非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")

特殊套管较小型的常见情况也会有所帮助。 FWIW,这只是长字符串列表切片速度的3倍,而小字符串则是4到5 的因素。

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

答案 4 :(得分:16)

如果您想要最快的方式,可以将itertoolsoperator.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

没有带连接的生成器这样的东西,传递一个总是会变慢,因为python将首先使用内容构建一个列表,因为它对数据进行了两次传递,一个用于计算所需的大小,一个实际上进行使用生成器无法实现的连接:

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

此外,如果您有不同的长度字符串并且您不想丢失数据,则可以使用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的建议是迄今为止最快的:

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 :(得分:12)

您也可以使用mapoperator.add执行此操作:

from operator import add

u = 'AAAAA'
l = 'aaaaa'

s = "".join(map(add, u, l))

<强>输出

'AaAaAaAaAa'

第一个可迭代u中的每个元素和第二个可迭代l中的第一个元素需要什么映射,并应用作为第一个参数add提供的函数。然后加入就加入了他们。

答案 6 :(得分:9)

吉姆的答案很棒,但如果您不介意几种进口,这里是我最喜欢的选择:

from functools import reduce
from operator import add

reduce(add, map(add, u, l))

答案 7 :(得分: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:]])

答案 8 :(得分:5)

我喜欢使用两个for,变量名称可以提示/提醒正在发生的事情:

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

答案 9 :(得分:4)

只是添加另一种更基本的方法:

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

答案 10 :(得分:3)

可能比当前领先的解决方案更快更短:

from itertools import chain

u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'

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

战略速度方面是尽可能多地在C级做。同样的zip_longest()修复了不均匀的字符串,它会出现在与chain()相同的模块中,所以不能在那里给我太多的点数!

我提出的其他解决方案:

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

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

答案 11 :(得分:3)

感觉有点不智能,不考虑这里的双列表理解答案,用O(1)努力处理n字符串:

"".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)
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'

像许多答案一样,最快?可能不是,但简单而灵活。此外,没有太多增加的复杂性,这比接受的答案略快(通常,字符串添加在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

答案 12 :(得分:3)

您可以使用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

答案 13 :(得分:2)

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

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

print result
# 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'