reverse
파이썬 str
객체 에는 내장 함수 가 없습니다 . 이 방법을 구현하는 가장 좋은 방법은 무엇입니까?
매우 간결한 답변을 제공하는 경우 효율성을 자세히 설명하십시오. 예를 들어 str
객체가 다른 객체로 변환 되는지 여부 등
답변
어때요?
>>> 'hello world'[::-1]
'dlrow olleh'
이것은 확장 슬라이스 구문입니다. 그것은 수행하여 작동합니다 [begin:end:step]
– 시작 오프 종료 떠나 -1 단계를 지정하여,이 문자열은 반전.
답변
@ Paolo ‘s s[::-1]
가 가장 빠릅니다. 느린 접근 방식 (더 읽기 쉽지만 논쟁의 여지가 있음)은 ''.join(reversed(s))
입니다.
답변
문자열에 역 기능을 구현하는 가장 좋은 방법은 무엇입니까?
이 질문에 대한 나의 경험은 학문적입니다. 그러나 빠른 답변을 찾고있는 전문가라면 다음 단계를 따르는 조각을 사용하십시오 -1
.
>>> 'a string'[::-1]
'gnirts a'
이상의 판독 가능 (하지만 느린 인해 반복자를 제공 할 때 형태를리스트에 가입하는 방법 이름 조회 및 사실) str.join
:
>>> ''.join(reversed('a string'))
'gnirts a'
가독성과 재사용 성을 위해 슬라이스를 함수에 넣습니다.
def reversed_string(a_string):
return a_string[::-1]
그리고:
>>> reversed_string('a_string')
'gnirts_a'
더 긴 설명
학술 박람회에 관심이 있으시면 계속 읽으십시오.
파이썬의 str 객체에는 내장 역 기능이 없습니다.
다음은 알아야 할 Python 문자열에 대한 몇 가지 사항입니다.
-
파이썬에서 문자열은 불변 입니다. 문자열을 변경해도 문자열은 수정되지 않습니다. 새로운 것을 만듭니다.
-
문자열은 슬라이스 가능합니다. 문자열을 슬라이스하면 주어진 증분에 의해 문자열의 한 지점에서 앞뒤로 다른 지점으로 새 문자열이 제공됩니다. 아래 첨자에서 슬라이스 표기법 또는 슬라이스 객체를 사용합니다.
string[subscript]
아래 첨자는 중괄호 안에 콜론을 포함시켜 슬라이스를 만듭니다.
string[start:stop:step]
중괄호 외부에서 슬라이스를 만들려면 슬라이스 객체를 만들어야합니다.
slice_obj = slice(start, stop, step)
string[slice_obj]
읽을 수있는 접근법 :
''.join(reversed('foo'))
읽을 수는 있지만 str.join
다른 호출 된 함수에서 문자열 메소드를 호출해야합니다 . 이것을 함수에 넣자. 다시 돌아올 것이다.
def reverse_string_readable_answer(string):
return ''.join(reversed(string))
가장 뛰어난 접근 방식 :
리버스 슬라이스를 사용하는 것이 훨씬 빠릅니다.
'foo'[::-1]
그러나 조각이나 원래 저자의 의도에 익숙하지 않은 사람이 어떻게 이것을 더 읽기 쉽고 이해하기 쉽게 만들 수 있습니까? 아래 첨자 표기법 외부에서 슬라이스 객체를 만들어 설명적인 이름을 지정하고 첨자 표기법으로 전달해 봅시다.
start = stop = None
step = -1
reverse_slice = slice(start, stop, step)
'foo'[reverse_slice]
기능으로 구현
실제로 이것을 함수로 구현하려면 설명적인 이름을 사용하기에 의미가 명확하다고 생각합니다.
def reversed_string(a_string):
return a_string[::-1]
사용법은 간단합니다.
reversed_string('foo')
선생님이 원하는 것 :
강사가 있으면 빈 문자열로 시작하여 이전 문자열에서 새 문자열을 작성하기를 원할 것입니다. 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
문자열은 불변 이기 때문에 이론적으로 나쁩니다. 따라서 문자열을 문자로 추가하는 것처럼 보일 때마다 new_string
이론적으로 매번 새 문자열을 만듭니다! 그러나 CPython은 특정 경우에이를 최적화하는 방법을 알고 있으며,이 경우는 사소한 경우입니다.
모범 사례
이론적으로 더 나은 방법은 목록에서 하위 문자열을 수집하여 나중에 결합하는 것입니다.
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)
그러나 CPython에 대한 아래의 타이밍에서 볼 수 있듯이 CPython은 문자열 연결을 최적화 할 수 있기 때문에 실제로 시간이 더 오래 걸립니다.
타이밍
타이밍은 다음과 같습니다.
>>> 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은 문자열 연결을 최적화하지만 다른 구현에서는 그렇지 않을 수 있습니다 .
… a + = b 또는 a = a + b 형식의 명령문에 대해 CPython의 내부 문자열 연결의 효율적인 구현에 의존하지 마십시오. 이 최적화는 CPython에서도 취약하며 (일부 유형에서만 작동) 재 계산을 사용하지 않는 구현에는 전혀 존재하지 않습니다. 라이브러리의 성능에 민감한 부분에서는 ”.join () 형식을 대신 사용해야합니다. 이렇게하면 다양한 구현에서 선형 시간으로 연결이 발생합니다.
답변
빠른 답변 (TL; DR)
예
### example01 -------------------
mystring = 'coup_ate_grouping'
backwards = mystring[::-1]
print backwards
### ... or even ...
mystring = 'coup_ate_grouping'[::-1]
print mystring
### result01 -------------------
'''
gnipuorg_eta_puoc
'''
자세한 답변
배경
이 답변은 @odigity의 다음 우려를 해결하기 위해 제공됩니다.
와. Paolo가 제안한 솔루션에 의해 처음에는 깜짝 놀랐다. 그러나 그것은 첫 번째 의견을 읽었을 때 느꼈던 공포에 뒷좌석을 가져 갔다. 나는 그렇게 밝은 공동체가 그렇게 기본적인 방법으로 그러한 암호 방법을 사용하는 것이 좋은 생각이라고 생각하기에 너무 불안합니다. 왜 s.reverse ()가 아닌가?
문제
- 문맥
- 파이썬 2.x
- 파이썬 3.x
- 대본:
- 개발자가 문자열을 변환하려고합니다
- 변환은 모든 문자의 순서를 반대로하는 것입니다
해결책
- example01은 확장 슬라이스 표기법을 사용하여 원하는 결과를 생성합니다 .
함정
- 개발자는 다음과 같은 것을 기대할 수 있습니다.
string.reverse()
- 새로운 관용어 (일명 ” pythonic “) 솔루션은 새로운 개발자가 읽지 못할 수 있습니다.
- 개발자는
string.reverse()
슬라이스 표기법을 피하기 위해 자신의 버전을 구현하려는 유혹을받을 수 있습니다 . - 슬라이스 표기법의 출력은 일부 경우에 반 직관적 일 수 있습니다.
- 예를 들어 example02 참조
print 'coup_ate_grouping'[-4:] ## => 'ping'
- 에 비해
print 'coup_ate_grouping'[-4:-1] ## => 'pin'
- 에 비해
print 'coup_ate_grouping'[-1] ## => 'g'
- 색인 생성의 다른 결과로 인해
[-1]
일부 개발자가 벗어날 수 있습니다.
- 예를 들어 example02 참조
이론적 해석
파이썬은 특별한 상황을 알고 있습니다 : 문자열은 반복 가능한 타입입니다.
string.reverse()
방법 을 배제하는 한 가지 근거 는 파이썬 개발자에게이 특별한 상황의 힘을 활용하도록 인센티브를주는 것입니다.
간단히 말하면, 이는 단순히 다른 프로그래밍 언어의 배열과 마찬가지로 문자열의 각 개별 문자를 요소의 순차적 배열의 일부로 쉽게 조작 할 수 있음을 의미합니다.
이것이 어떻게 작동하는지 이해하기 위해 example02를 검토하면 좋은 개요를 제공 할 수 있습니다.
예 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'
결론
인지 부하는 파이썬에서 슬라이스 표기법 작품이 실제로 언어를 학습에 많은 시간을 투자하지 않으 일부 어답터와 개발자를 위해 너무 많이있을 수 있습니다 방법을 이해와 관련.
그럼에도 불구하고 일단 기본 원리가 이해되면 고정 문자열 조작 방법에 대한이 접근 방식의 힘이 상당히 유리할 수 있습니다.
다르게 생각하는 사람들에게는 람다 함수, 반복자 또는 간단한 일회성 함수 선언과 같은 대체 방법이 있습니다.
원하는 경우 개발자는 자신의 string.reverse () 메서드를 구현할 수 있지만 파이썬의 이러한 측면에 대한 이론적 근거를 이해하는 것이 좋습니다.
또한보십시오
답변
기존 답변은 Unicode Modifiers / grapheme 클러스터가 무시되는 경우에만 정확합니다. 나중에 그 문제를 다룰 것이지만 먼저 몇 가지 반전 알고리즘의 속도를 살펴보십시오.
list_comprehension : min: 0.6μs, mean: 0.6μs, max: 2.2μs
reverse_func : min: 1.9μs, mean: 2.0μs, max: 7.9μs
reverse_reduce : min: 5.7μs, mean: 5.9μs, max: 10.2μs
reverse_loop : min: 3.0μs, mean: 3.1μs, max: 6.8μs
list_comprehension : min: 4.2μs, mean: 4.5μs, max: 31.7μs
reverse_func : min: 75.4μs, mean: 76.6μs, max: 109.5μs
reverse_reduce : min: 749.2μs, mean: 882.4μs, max: 2310.4μs
reverse_loop : min: 469.7μs, mean: 577.2μs, max: 1227.6μs
리스트 이해 시간이reversed = string[::-1]
)이 모든 경우에 가장 낮습니다 (오타를 수정 한 후에도).
문자열 반전
상식적으로 문자열을 반대로 바꾸려면 더 복잡합니다. 예를 들어, 다음 문자열을 사용하십시오 ( 갈색 손가락은 왼쪽 , 노란색 손가락은 위쪽 ). 이것들은 두 개의 grapheme이지만 3 개의 유니 코드 코드 포인트입니다. 추가는 스킨 수정 자 입니다.
example = "???"
하지만 주어진 방법 중 하나 그것을 반대하는 경우, 당신이 얻을 갈색 손가락이 가리키는 , 노란색 손가락으로 왼쪽을 가리키는 . 그 이유는 “갈색”색상 수정자가 여전히 중간에 있고 그 이전의 모든 것에 적용되기 때문입니다. 그래서 우리는
- U : 손가락 가리키는
- M : 갈색 수정 제
- L : 왼쪽을 가리키는 손가락
과
original: LMU
reversed: UML (above solutions)
reversed: ULM (correct reversal)
Unicode Grapheme Clusters 는 수정 자 코드 포인트보다 조금 더 복잡합니다. 운 좋게도 grapheme 을 처리하기위한 라이브러리가 있습니다 .
>>> import grapheme
>>> g = grapheme.graphemes("???")
>>> list(g)
['??', '?']
따라서 정답은
def reverse_graphemes(string):
g = list(grapheme.graphemes(string))
return ''.join(g[::-1])
또한 가장 느립니다.
list_comprehension : min: 0.5μs, mean: 0.5μs, max: 2.1μs
reverse_func : min: 68.9μs, mean: 70.3μs, max: 111.4μs
reverse_reduce : min: 742.7μs, mean: 810.1μs, max: 1821.9μs
reverse_loop : min: 513.7μs, mean: 552.6μs, max: 1125.8μs
reverse_graphemes : min: 3882.4μs, mean: 4130.9μs, max: 6416.2μs
코드
#!/usr/bin/env python
import numpy as np
import random
import timeit
from functools import reduce
random.seed(0)
def main():
longstring = ''.join(random.choices("ABCDEFGHIJKLM", k=2000))
functions = [(list_comprehension, 'list_comprehension', longstring),
(reverse_func, 'reverse_func', longstring),
(reverse_reduce, 'reverse_reduce', longstring),
(reverse_loop, 'reverse_loop', longstring)
]
duration_list = {}
for func, name, params in functions:
durations = timeit.repeat(lambda: func(params), repeat=100, number=3)
duration_list[name] = list(np.array(durations) * 1000)
print('{func:<20}: '
'min: {min:5.1f}μs, mean: {mean:5.1f}μs, max: {max:6.1f}μs'
.format(func=name,
min=min(durations) * 10**6,
mean=np.mean(durations) * 10**6,
max=max(durations) * 10**6,
))
create_boxplot('Reversing a string of length {}'.format(len(longstring)),
duration_list)
def list_comprehension(string):
return string[::-1]
def reverse_func(string):
return ''.join(reversed(string))
def reverse_reduce(string):
return reduce(lambda x, y: y + x, string)
def reverse_loop(string):
reversed_str = ""
for i in string:
reversed_str = i + reversed_str
return reversed_str
def create_boxplot(title, duration_list, showfliers=False):
import seaborn as sns
import matplotlib.pyplot as plt
import operator
plt.figure(num=None, figsize=(8, 4), dpi=300,
facecolor='w', edgecolor='k')
sns.set(style="whitegrid")
sorted_keys, sorted_vals = zip(*sorted(duration_list.items(),
key=operator.itemgetter(1)))
flierprops = dict(markerfacecolor='0.75', markersize=1,
linestyle='none')
ax = sns.boxplot(data=sorted_vals, width=.3, orient='h',
flierprops=flierprops,
showfliers=showfliers)
ax.set(xlabel="Time in ms", ylabel="")
plt.yticks(plt.yticks()[0], sorted_keys)
ax.set_title(title)
plt.tight_layout()
plt.savefig("output-string.png")
if __name__ == '__main__':
main()
답변
1. 슬라이스 표기법 사용
def rev_string(s):
return s[::-1]
2. reversed () 함수 사용
def rev_string(s):
return ''.join(reversed(s))
3. 재귀 사용
def rev_string(s):
if len(s) == 1:
return s
return s[-1] + rev_string(s[:-1])
답변
덜 복잡한 방법은 다음과 같습니다.
string = 'happy'
print(string)
‘행복’
string_reversed = string[-1::-1]
print(string_reversed)
‘이파’
영어로 [-1 ::-1]은 다음과 같이 읽습니다.
“-1부터 시작하여 -1 단계까지 진행하십시오.”