Python 切换字符串中的每对字符

Python 切换字符串中的每对字符,python,string,performance,python-2.7,Python,String,Performance,Python 2.7,例如,具有以下字符串: abcdefghijklmnopqrstuvwxyz 结果应该是这样的: badcfehgjilknmporqtsvuxwzy 我该怎么做呢 我想到了一些效率不高的事情,例如: s = str(range(ord('a'), ord('z') + 1)) new_s = '' for i in xrange(len(s)): if i != 0 and i % 2 == 0: new_s += '_' + s[i] else:

例如,具有以下字符串:

abcdefghijklmnopqrstuvwxyz
结果应该是这样的:

badcfehgjilknmporqtsvuxwzy
我该怎么做呢

我想到了一些效率不高的事情,例如:

s = str(range(ord('a'), ord('z') + 1))
new_s = ''
for i in xrange(len(s)):
    if i != 0 and i % 2 == 0:
        new_s += '_' + s[i]
    else:
        new_s += s[i]
# Now it should result in a string such as 'ab_cd_ef_...wx_yz'
l = new_s.split('_')
for i in xrange(len(l)):
    l[i] = l[i][::-1]
result = str(l)
还有更好的办法吗?某种更有效或更通用的方法,这样我也可以更容易地使用3个字母?

您可以使用
zip()
函数,该函数将返回元组列表作为
[(b,a),(d,c),…]
,并将
.join()
方法应用于元组和列表的元素

a = "abcdefghijklmnopqrstuvwxyz"
# a[::2] = "acegikmoqsuwy"
# a[1::2] = "bdfhjlnprtvx"
print "".join("".join(i) for i in zip(a[1::2], a[::2]))
>>> badcfehgjilknmporqtsvuxwzy
编辑:按照@Ashwini和@TigerhawkT3的建议,要处理奇数长度字符串的情况,您可以将代码更改为:

print "".join("".join(i) for i in zip(a2, a1)) + a[-1] if len(a)%2 else '' 

我不确定首先使用正则表达式是否总是最好的做法,但它似乎适合这里。找到2个字符,按相反的顺序将其细分,然后继续,直到您的字符串用完为止

import re

>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> re.sub(r'(.)(.)', "\g<2>\g<1>", s)
'badcfehgjilknmporqtsvuxwzy'
重新导入
>>>s=“abcdefghijklmnopqrstuvxyz”
>>>re.sub(r'(),“\g\g”,s)
“badcfehgjilknmporqtsvuxwzy”
易于推广到其他数量的字符:

>>> def swap3(txt):
...    return re.sub(r'(.)(.)(.)', '\g<3>\g<2>\g<1>', txt)
...
>>> swap3(s)
'cbafedihglkjonmrqputsxwvyz'
def swap3(txt): ... 返回re.sub(r'(.),'\g\g\g',txt) ... >>>swap3(s) “cbafedihglkjonmrqputsxwvyz” 或

def parameterizedSwap(txt,numChars): ... 帕特=r“()”*纽卡 ... 替换=“”.join([“\g”.format(numChars-i)表示范围内的i(numChars)]) ... 返回子目录(pat、replace、txt) ... >>>参数化交换(s,5) “edcbajihgfonmlktsrqpyxwvuz”
这与其他答案非常相似,只是更明确地解释了它对代码读者所做的事情,迭代成对的字符并将它们与
izip()
连接起来相当简单,奇数字符串长度的处理可以通过在末尾添加条件连接来处理

from itertools import izip

s = "abcdefghijklmnopqrstuvwxyz"
print ("".join(((pair[1]+pair[0]) for pair in izip(*[iter(s)]*2))) +
            (s[-1] if len(s) % 2 else ''))
正如@Ashwini在评论中所建议的,同样的事情可以通过使用
izip_longest()
而不是
izip()
更简洁地完成

from itertools import izip_longest

s = "abcdefghijklmnopqrstuvwxyz"
print "".join(((pair[1]+pair[0]) for pair in
                    izip_longest(*[iter(s)]*2, fillvalue='')))

一种不使用任何导入的解决方案是将字符串转换为迭代器,并在迭代过程中通过调用迭代器上的next获取下一个字符:

>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> it = iter(s)
>>> ''.join(next(it, '') + c for c in it )
'badcfehgjilknmporqtsvuxwzy'
计时:

>>> s = "abcdefghijklmnopqrstuvwxyz" * 10**5
>>> def func_next_no_cache(s):
    it = iter(s)
    return ''.join([next(it, '') + c for c in it])
...
>>> %timeit func_next_no_cache(s)
1 loops, best of 3: 291 ms per loop
但是对
next
的调用实际上减慢了它的速度,因为为了找到
next
Python必须从本地范围开始进入内置,让我们缓存它并重试:

>>> def func_next_cache(s, next=next):
    it = iter(s)
    return ''.join([next(it, '') + c for c in it])
...
>>> %timeit func_next_cache(s)
1 loops, best of 3: 241 ms per loop
但最快的解决方案是使用itertools。izip_longest:

>>> from itertools import izip_longest
>>> def func_izip_l(s):
    it = iter(s)
    return "".join([b+a for a, b in  izip_longest(it, it, fillvalue='')])
...
>>> %timeit func_izip_l(s)

1 loops, best of 3: 209 ms per loop
@Joran的代码在与列表而不是生成器表达式一起使用时也与此代码非常接近,但它在内存中创建了两个额外的字符串:

>>> %timeit "".join([b+a for a, b in izip_longest(s[::2], s[1::2], fillvalue="")])
1 loops, best of 3: 212 ms per loop


注意我们应该始终向
str.join提供
列表
,如果速度是一个问题:

长度是否总是相等?@thefourtheye No**。顺便说一句,我发布的方法仍然适用于长度不均匀的字符串。如果想要得到3个字符,您希望得到什么结果?
it=iter(s);“”。加入(下一个(它,)+c代表c)
简洁的IMO.@AshwiniChaudhary请发布一个答案,这样我可以为未来的读者标记它是最好的,你的答案是最快的。同意,虽然分块和压缩是我第一次想到的方法,但regex更容易阅读和扩展。是的,这就是为什么我投票支持这个。。。漂亮、简短且易于阅读(可能使第二个参数可选(.?)来处理奇数长度字符串?)奇数长度字符串如何?更新了我的答案,谢谢@AshwiniChaudhary.Thank@TigerhawkT3临时修改了我的答案内容。这对于奇数长度字符串也将失败
izip_longest
with
fillvalue='
将是这里的通用解决方案。最快的解决方案。谢谢:)
>>> def func_next_cache(s, next=next):
    it = iter(s)
    return ''.join([next(it, '') + c for c in it])
...
>>> %timeit func_next_cache(s)
1 loops, best of 3: 241 ms per loop
>>> from itertools import izip_longest
>>> def func_izip_l(s):
    it = iter(s)
    return "".join([b+a for a, b in  izip_longest(it, it, fillvalue='')])
...
>>> %timeit func_izip_l(s)

1 loops, best of 3: 209 ms per loop
>>> %timeit "".join([b+a for a, b in izip_longest(s[::2], s[1::2], fillvalue="")])
1 loops, best of 3: 212 ms per loop