例如,拥有字符串:
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个字母来处理它?</ p>
答案 0 :(得分:7)
您可以使用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 ''
答案 1 :(得分:3)
不使用任何导入的一个解决方案是将字符串转换为迭代器,并在迭代期间通过在迭代器上调用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
注意如果担心速度问题,我们应始终将list
提供给str.join
:https://stackoverflow.com/a/9061024/846892
答案 2 :(得分:2)
我不确定首先达到正则表达式总是最好的做法,但它似乎适合这里。找到2个字符,按相反的顺序将它们分开,然后继续,直到你没有字符串。
import re
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> re.sub(r'(.)(.)', "\g<2>\g<1>", s)
'badcfehgjilknmporqtsvuxwzy'
轻松推广到其他数量的字符:
>>> def swap3(txt):
... return re.sub(r'(.)(.)(.)', '\g<3>\g<2>\g<1>', txt)
...
>>> swap3(s)
'cbafedihglkjonmrqputsxwvyz'
或
>>> def parameterizedSwap(txt, numChars):
... pat = r"(.)" * numChars
... replace = "".join(["\g<{0}>".format(numChars-i) for i in range(numChars)])
... return re.sub(pat, replace, txt)
...
>>> parameterizedSwap(s, 5)
'edcbajihgfonmlktsrqpyxwvuz'
答案 3 :(得分:1)
from itertools import izip_longest as myzip
"".join(b+a for a,b in myzip(a[::2],a[1::2],fillvalue=""))
这与其他答案非常相似,只是在向代码的读者解释它正在做什么时更明确一些
答案 4 :(得分:0)
from itertools import zip, chain
c1 = [c for i, c in enumerate(s) if i % 2 == 0]
c2 = [c for i, c in enumerate(s) if i % 2 == 1]
''.join(chain.from_iterable(zip(c2,c1)))
答案 5 :(得分:0)
迭代一对字符并用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 ''))
使用izip_longest()
代替izip()
可以更简洁地完成同样的事情,正如@Ashwini在评论中所暗示的那样。
from itertools import izip_longest
s = "abcdefghijklmnopqrstuvwxyz"
print "".join(((pair[1]+pair[0]) for pair in
izip_longest(*[iter(s)]*2, fillvalue='')))