2015-06-03 20 views
5

Ví dụ, có chuỗi:Chuyển tất cả các cặp ký tự trong một chuỗi

abcdefghijklmnopqrstuvwxyz 

nên kết quả trong một cái gì đó như thế này:

badcfehgjilknmporqtsvuxwzy 

Làm thế nào để mặc đi về nó?

Tôi nghĩ đến một cái gì đó không phải là rất hiệu quả, chẳng hạn như:

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) 

Có cách nào tốt hơn? Một số cách hiệu quả hơn hoặc tổng quát hơn vì vậy tôi cũng có thể sử dụng 3 chữ cái dễ dàng hơn?

+0

chiều dài Sẽ là thậm chí luôn? – thefourtheye

+0

@thefourtheye Không **. Nhân tiện, cách tôi đăng vẫn hoạt động với một chuỗi có chiều dài không bằng nhau. – Jack

+0

Bạn mong đợi kết quả như thế nào nếu bạn muốn nhận được 3 ký tự? – thefourtheye

Trả lời

3

Một giải pháp mà không sử dụng bất kỳ hàng nhập khẩu sẽ được chuyển đổi chuỗi đến một iterator và trong thời gian lặp lấy ký tự tiếp theo bằng cách gọi tiếp theo trên iterator:

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

Thời gian:

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

Nhưng các cuộc gọi đến next đang thực sự làm chậm xuống vì tìm kiếm next Python có để đi đến builtins bắt đầu từ phạm vi địa phương, chúng ta hãy nhớ cache nó và thử lại:

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

Nhưng giải pháp nhanh nhất sẽ được sử dụng 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 

@ đang Joran cũng rất gần với trang này khi được sử dụng với một danh sách thay vì biểu hiện máy phát điện, nhưng nó tạo ra hai chuỗi bổ sung trong bộ nhớ:

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

Note rằng chúng ta nên luôn luôn ăn một list-str.join nếu tốc độ là một mối quan tâm: https://stackoverflow.com/a/9061024/846892

+0

Giải pháp nhanh nhất. Cảm ơn bạn :) – Jack

7

Bạn có thể sử dụng hàm zip() để trả lại danh sách các bộ dữ liệu là [(b,a), (d,c), ...] và áp dụng phương thức .join() cho cả các thành phần của bộ và danh sách.

a = "abcdefghijklmnopqrstuvwxyz" 
# a[::2] = "acegikmoqsuwy" 
# a[1::2] = "bdfhjlnprtvx" 
print "".join("".join(i) for i in zip(a[1::2], a[::2])) 
>>> badcfehgjilknmporqtsvuxwzy 

EDIT: Để xử lý các trường hợp chuỗi dài lẻ, theo đề nghị của @Ashwini và @ TigerhawkT3, bạn có thể thay đổi các mã như:

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

Điều gì về chuỗi dài lẻ? –

+0

Thêm '+ a [-1] nếu len (a)% 2 else ''' sẽ thực hiện thủ thuật. – TigerhawkT3

+0

Đã cập nhật câu trả lời của tôi, Cảm ơn @AshwiniChaudhary. – ZdaR

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

Tôi không chắc chắn rằng việc tiếp cận các cụm từ thông dụng trước tiên luôn là điều tốt nhất để làm, nhưng dường như nó phù hợp ở đây. Tìm 2 ký tự, đặt chúng theo thứ tự ngược lại và tiếp tục cho đến khi bạn hết chuỗi.

import re 

>>> s = "abcdefghijklmnopqrstuvwxyz" 
>>> re.sub(r'(.)(.)', "\g<2>\g<1>", s) 
'badcfehgjilknmporqtsvuxwzy' 

Dễ dàng khái quát đến các số khác của nhân vật:

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

hoặc

>>> 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' 
+1

đồng ý rằng, mặc dù chunking và zip là cách tiếp cận đầu tiên của tôi mặc dù, regex là dễ dàng hơn để đọc và mở rộng hơn. –

+0

yeah thats lý do tại sao tôi upvoted này ... đẹp và ngắn và rất dễ đọc (có thể làm cho đối số thứ 2 tùy chọn (.?) Để xử lý các chuỗi dài lẻ?) –

+0

... còn lại như một bài tập cho người đọc ... :) – bgporter

1
from itertools import izip_longest as myzip 
"".join(b+a for a,b in myzip(a[::2],a[1::2],fillvalue="")) 

này rất giống với những câu trả lời khác chỉ là một số những gì rõ ràng hơn trong việc giải thích những gì nó đang thực hiện cho người đọc mã số

0

Lặp lại các cặp ký tự và nối chúng với izip() là khá đơn giản và việc xử lý các độ dài chuỗi lẻ có thể được xử lý bằng cách thêm một kết nối có điều kiện vào cuối.

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

Điều tương tự có thể được thực hiện một chút ngắn gọn hơn bằng cách sử izip_longest() thay vì izip(), như @Ashwini gợi ý trong nhận xét.

from itertools import izip_longest 

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

Điều này cũng sẽ không thành công đối với các chuỗi dài lẻ. 'izip_longest' với' fillvalue = '' 'sẽ là một giải pháp chung ở đây. –

+0

@Ashwini: Điểm tốt - cố định. – martineau

Các vấn đề liên quan