Câu hỏi Đảo ngược một chuỗi trong Python


Không có tích hợp reverse chức năng cho Python str vật. Cách tốt nhất để triển khai phương pháp này là gì?

Nếu cung cấp một câu trả lời rất ngắn gọn, hãy giải thích về hiệu quả của nó. Ví dụ, cho dù str đối tượng được chuyển đổi thành một đối tượng khác, v.v.


1071
2018-05-31 02:10


gốc




Các câu trả lời:


Làm thế nào về:

>>> 'hello world'[::-1]
'dlrow olleh'

Đây là lát mở rộng cú pháp. Nó hoạt động bằng cách làm [begin:end:step] - bằng cách để bắt đầu và kết thúc và chỉ định một bước -1, nó đảo ngược một chuỗi.


2220
2018-05-31 02:11



Điều đó không làm việc cho utf8 mặc dù .. Tôi cần phải làm điều này là tốt b = a.decode('utf8')[::-1].encode('utf8') nhưng cảm ơn đúng hướng! - Ricky Levi
@RickyLevi Nếu .decode('utf8') là bắt buộc, nó có nghĩa là a không chứa bất kỳ đối tượng chuỗi nào, thay vì byte. - Shiplu Mokaddim
@RickyLevi Tôi có thể đảo ngược chuỗi utf8 mà không cần giải mã và mã hóa. - Himadri
@Himadri Nó quan trọng nếu đó là Python 3 hoặc Python 2.7 - Csaba Toth
Tôi đã sử dụng cái này và sự kết hợp của join trả lời dưới đây để tạo địa chỉ email gửi (giả) của tập lệnh. scriptname="".join(os.path.basename(sys.argv[0])[::-1].split('.')[1:])[::-1] ; computername=socket.gethostname() ; msgfrom=scriptname + '_on_' + computername + '@example.com' - user208145


@ Paolo's s[::-1] là nhanh nhất; một cách tiếp cận chậm hơn (có thể dễ đọc hơn, nhưng điều đó có thể gây tranh cãi) là ''.join(reversed(s)).


217
2018-05-31 02:13



Tốc độ này chậm hơn khoảng 3 lần. - oneself
Và một bình luận nhanh chóng để nói những gì nó sẽ giải thích nó tốt hơn so với sử dụng phiên bản này chậm hơn! - tburrows13
nó chậm hơn vì join  có để xây dựng danh sách để có thể nhận được kích thước. ''.join(list(reversed(s))) có thể hơi nhanh hơn. - Jean-François Fabre


Cách tốt nhất để thực hiện chức năng đảo ngược cho chuỗi là gì?

Kinh nghiệm của riêng tôi với câu hỏi này là học tập. Tuy nhiên, nếu bạn là một người chuyên nghiệp đang tìm kiếm câu trả lời nhanh, hãy sử dụng một lát mà -1:

>>> 'a string'[::-1]
'gnirts a'

hoặc dễ đọc hơn (nhưng chậm hơn do tra cứu tên phương thức và thực tế là tham gia tạo thành một danh sách khi được cung cấp một trình vòng lặp), str.join:

>>> ''.join(reversed('a string'))
'gnirts a'

hoặc để dễ đọc và có thể sử dụng lại, hãy đặt lát cắt vào một chức năng

def reversed_string(a_string):
    return a_string[::-1]

và sau đó:

>>> reversed_string('a_string')
'gnirts_a'

Giải thích dài hơn

Nếu bạn quan tâm đến triển lãm học tập, hãy tiếp tục đọc.

Không có hàm đảo ngược tích hợp trong đối tượng str của Python.

Dưới đây là một vài điều về chuỗi của Python bạn nên biết:

  1. Trong Python, chuỗi là bất biến. Thay đổi một chuỗi không sửa đổi chuỗi. Nó tạo ra một cái mới.

  2. Chuỗi có thể cắt xén. Cắt một chuỗi cung cấp cho bạn một chuỗi mới từ một điểm trong chuỗi, ngược hoặc tiến, đến một điểm khác, theo số gia tăng. Chúng có ký hiệu slice hoặc một đối tượng slice trong một subscript:

    string[subscript]
    

Chỉ số này tạo một lát bằng cách bao gồm dấu hai chấm trong dấu ngoặc ôm:

    string[start:stop:step]

Để tạo một slice bên ngoài các dấu ngoặc, bạn cần tạo một đối tượng slice:

    slice_obj = slice(start, stop, step)
    string[slice_obj]

Một cách tiếp cận có thể đọc được:

Trong khi ''.join(reversed('foo')) có thể đọc được, nó đòi hỏi phải gọi một phương thức chuỗi, str.join, trên một hàm được gọi khác, có thể khá chậm. Hãy đặt điều này vào một hàm - chúng ta sẽ quay lại với nó:

def reverse_string_readable_answer(string):
    return ''.join(reversed(string))

Cách tiếp cận hiệu quả nhất:

Nhanh hơn nhiều là sử dụng một lát đảo ngược:

'foo'[::-1]

Nhưng làm thế nào chúng ta có thể làm cho điều này dễ đọc hơn và dễ hiểu hơn đối với một người ít quen thuộc hơn với các lát hoặc ý định của tác giả gốc? Hãy tạo một đối tượng slice bên ngoài ký hiệu chỉ số, đặt cho nó một tên mô tả và chuyển nó tới ký hiệu chỉ số.

start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]

Thực hiện chức năng

Để thực sự thực hiện điều này như một hàm, tôi nghĩ nó đủ rõ ràng về mặt ngữ nghĩa để chỉ đơn giản sử dụng một tên mô tả:

def reversed_string(a_string):
    return a_string[::-1]

Và cách sử dụng đơn giản là:

reversed_string('foo')

Những gì giáo viên của bạn có thể muốn:

Nếu bạn có một người hướng dẫn, họ có thể muốn bạn bắt đầu bằng một chuỗi rỗng và xây dựng một chuỗi mới từ chuỗi cũ. Bạn có thể làm điều này với cú pháp và chữ thuần túy bằng cách sử dụng vòng lặp while:

def reverse_a_string_slowly(a_string):
    new_string = ''
    index = len(a_string)
    while index:
        index -= 1                    # index = index - 1
        new_string += a_string[index] # new_string = new_string + character
    return new_string

Đây là lý thuyết xấu bởi vì, hãy nhớ, chuỗi là bất biến - vì vậy mỗi khi có vẻ như bạn đang thêm một ký tự vào new_stringvề mặt lý thuyết, tạo chuỗi mới mỗi lần! Tuy nhiên, CPython biết cách tối ưu hóa điều này trong một số trường hợp, trong đó trường hợp tầm thường này là một.

Thực hành tốt nhất

Về mặt lý thuyết tốt hơn là thu thập các chất nền của bạn trong một danh sách và tham gia sau:

def reverse_a_string_more_slowly(a_string):
    new_strings = []
    index = len(a_string)
    while index:
        index -= 1                       
        new_strings.append(a_string[index])
    return ''.join(new_strings)

Tuy nhiên, như chúng ta sẽ thấy trong thời gian dưới đây cho CPython, điều này thực sự mất nhiều thời gian hơn, bởi vì CPython có thể tối ưu hóa chuỗi nối.

Thời gian

Dưới đây là thời gian:

>>> a_string = 'amanaplanacanalpanama' * 10
>>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string)))
10.38789987564087
>>> min(timeit.repeat(lambda: reversed_string(a_string)))
0.6622700691223145
>>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string)))
25.756799936294556
>>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string)))
38.73570013046265

CPython tối ưu hóa chuỗi nối, trong khi các triển khai khác có thể không:

... không dựa vào việc thực hiện hiệu quả của CPython trong chuỗi nối tại chỗ cho các câu lệnh dưới dạng a + = b hoặc a = a + b. Tối ưu hóa này là mong manh ngay cả trong CPython (nó chỉ hoạt động đối với một số loại) và không có mặt ở tất cả trong triển khai mà không sử dụng refcounting. Trong các phần nhạy cảm về hiệu suất của thư viện, thay vào đó, biểu mẫu'join (). ' Điều này sẽ đảm bảo rằng việc ghép nối xảy ra trong thời gian tuyến tính trên nhiều triển khai khác nhau.


168
2018-01-08 15:32





Trả lời nhanh (TL; DR)

Thí dụ

### example01 -------------------
mystring  =   'coup_ate_grouping'
backwards =   mystring[::-1]
print backwards

### ... or even ...
mystring  =   'coup_ate_grouping'[::-1]
print mystring

### result01 -------------------
'''
gnipuorg_eta_puoc
'''

Câu trả lời chi tiết

Lý lịch

Câu trả lời này được cung cấp để giải quyết mối quan tâm sau từ @odigity:

Wow. Ban đầu tôi kinh hoàng bởi giải pháp mà Paolo đề xuất, nhưng   ngồi xuống ghế sau nỗi kinh hoàng mà tôi cảm thấy khi đọc cuốn đầu tiên   nhận xét: "Đó là rất pythonic. Tốt công việc!" Tôi rất băn khoăn như vậy   một cộng đồng sáng sủa nghĩ rằng sử dụng các phương pháp khó hiểu như vậy   cơ bản là một ý tưởng hay. Tại sao nó không chỉ là s.reverse ()?

Vấn đề

  • Bối cảnh
    • Python 2.x
    • Python 3.x
  • Kịch bản:
    • Nhà phát triển muốn chuyển đổi chuỗi
    • Chuyển đổi là để đảo ngược thứ tự của tất cả các nhân vật

Dung dịch

Cạm bẫy

  • Nhà phát triển có thể mong đợi một cái gì đó như string.reverse()
  • Các thành ngữ bản địa (aka "NULL") giải pháp có thể không đọc được cho các nhà phát triển mới hơn
  • Nhà phát triển có thể bị cám dỗ để triển khai phiên bản của riêng họ string.reverse() để tránh ký hiệu slice.
  • Đầu ra của ký hiệu slice có thể phản trực giác trong một số trường hợp:
    • xem ví dụ: example02
      • print 'coup_ate_grouping'[-4:] ## => 'ping'
      • so với
      • print 'coup_ate_grouping'[-4:-1] ## => 'pin'
      • so với
      • print 'coup_ate_grouping'[-1] ## => 'g'
    • các kết quả khác nhau của việc lập chỉ mục trên [-1] có thể ném một số nhà phát triển

Lý do

Python có một trường hợp đặc biệt cần lưu ý: một chuỗi là một có thể lặp lại kiểu.

Một lý do để loại trừ một string.reverse() phương pháp là để cho các nhà phát triển python khuyến khích tận dụng sức mạnh của trường hợp đặc biệt này.

Trong thuật ngữ đơn giản, điều này đơn giản có nghĩa là mỗi ký tự riêng lẻ trong một chuỗi có thể dễ dàng hoạt động như một phần của sắp xếp tuần tự các phần tử, giống như các mảng trong các ngôn ngữ lập trình khác.

Để hiểu cách hoạt động của tính năng này, hãy xem lại ví dụ02 có thể cung cấp tổng quan tốt.

Ví dụ02

### example02 -------------------
## start (with positive integers)
print 'coup_ate_grouping'[0]  ## => 'c'
print 'coup_ate_grouping'[1]  ## => 'o' 
print 'coup_ate_grouping'[2]  ## => 'u' 

## start (with negative integers)
print 'coup_ate_grouping'[-1]  ## => 'g'
print 'coup_ate_grouping'[-2]  ## => 'n' 
print 'coup_ate_grouping'[-3]  ## => 'i' 

## start:end 
print 'coup_ate_grouping'[0:4]    ## => 'coup'    
print 'coup_ate_grouping'[4:8]    ## => '_ate'    
print 'coup_ate_grouping'[8:12]   ## => '_gro'    

## start:end 
print 'coup_ate_grouping'[-4:]    ## => 'ping' (counter-intuitive)
print 'coup_ate_grouping'[-4:-1]  ## => 'pin'
print 'coup_ate_grouping'[-4:-2]  ## => 'pi'
print 'coup_ate_grouping'[-4:-3]  ## => 'p'
print 'coup_ate_grouping'[-4:-4]  ## => ''
print 'coup_ate_grouping'[0:-1]   ## => 'coup_ate_groupin'
print 'coup_ate_grouping'[0:]     ## => 'coup_ate_grouping' (counter-intuitive)

## start:end:step (or start:end:stride)
print 'coup_ate_grouping'[-1::1]  ## => 'g'   
print 'coup_ate_grouping'[-1::-1] ## => 'gnipuorg_eta_puoc'

## combinations
print 'coup_ate_grouping'[-1::-1][-4:] ## => 'puoc'

Phần kết luận

Các tải nhận thức liên kết với sự hiểu biết cách ký hiệu slice hoạt động trong python thực sự có thể là quá nhiều đối với một số người dùng và nhà phát triển không muốn đầu tư nhiều thời gian vào việc học ngôn ngữ.

Tuy nhiên, một khi các nguyên tắc cơ bản được hiểu, sức mạnh của phương pháp này trên các phương thức thao tác chuỗi cố định có thể khá thuận lợi.

Đối với những người nghĩ khác, có những cách tiếp cận thay thế, chẳng hạn như hàm lambda, vòng lặp hoặc khai báo hàm đơn giản một lần.

Nếu muốn, một nhà phát triển có thể thực hiện phương thức string.reverse () của riêng mình, tuy nhiên nó là tốt để hiểu lý do đằng sau khía cạnh này của python.

Xem thêm


33
2017-10-31 22:24





Một cách ít phức tạp hơn để xem xét nó sẽ là:

string = 'happy'
print(string)

'vui mừng'

string_reversed = string[-1::-1]
print(string_reversed)

'yppah'

Bằng tiếng Anh [-1 :: - 1] đọc là:

"Bắt đầu từ -1, đi tất cả các con đường, thực hiện các bước -1"


10
2018-04-01 07:49





Đảo ngược một chuỗi trong python mà không sử dụng đảo ngược () hoặc [:: - 1]

def reverse(test):
    n = len(test)
    x=""
    for i in range(n-1,-1,-1):
        x += test[i]
    return x

4
2017-12-10 12:57



Bạn không nên sử dụng xrange vì bạn không cần danh sách, trong python 2? - UnitasBrooks


def reverse(input):
    return reduce(lambda x,y : y+x, input)

3
2018-06-26 04:25



Tôi bấm upvote, bởi vì tôi thích biểu hiện lambda này. Thật không may, đó là giải pháp hiệu quả nhất từ ​​tất cả các liệt kê ở trên (kiểm tra: Gist palindrome.py ) - oski86


sử dụng ký hiệu slice

def rev_string(s): 
    return s[::-1]

sử dụng hàm reversed ()

def rev_string(s): 
    return ''.join(reversed(s))

sử dụng đệ quy

def rev_string(s): 
    if len(s) == 1:
        return s

    return s[-1] + rev_string(s[:-1])

3
2018-05-20 22:24





Đây không phải là một trong những ưa thích:

def reverse(text):
    r_text = ''
    index = len(text) - 1

    while index >= 0:
        r_text += text[index] #string canbe concatenated
        index -= 1

    return r_text

print reverse("hello, world!")

2
2018-05-04 17:02