현재의 Python 프로젝트는 들어오는 패키지를 처리하기 위해 많은 문자열 분할이 필요합니다. 나는 꽤 느린 시스템에서이를 실행할 것이므로, 이것에 대해 가장 효율적인 방법이 무엇인지 궁금해하고 있었다. 문자열은 다음과 같이 뭔가를 포맷 할 것 :파이썬에서 문자열을 분할하는 가장 효율적인 방법
Item 1 | Item 2 | Item 3 <> Item 4 <> Item 5
설명 : 항목 5 항목 3 명을 초대 할 것입니다 동안이 특별한 예는, 처음 두 항목은 제목과 날짜입니다 목록에서 올 것입니다 (그 수는 0에서 n까지이며 n은 서버에 등록 된 사용자 수입니다.)
내가 무엇을보고, 나는 다음과 같은 옵션이 있습니다에서 :
- 을 반복
split()
- 를 사용하여 정규 표현식을 사용하고 정규식이 있습니다 (I 아직 생각하지 않은
- 다른 어떤 파이썬 기능을 기능 아마도 일부)
해결책 1은 |
에서 분할 한 다음 결과 목록의 마지막 요소를 솔루션이 아마 같은 정규 표현식을 초래하면서이 예를 들어 <>
을 :
((.+)|)+((.+)(<>)?)+
좋아,이 정규식은 끔찍, 나는 나 자신을 볼 수 있습니다. 또한 테스트되지 않았습니다. 그러나 당신은 아이디어를 얻습니다.
이제 나는 a)가 가장 적은 시간이 걸리고 b) 이상적으로는 최소 메모리를 사용하는 방법을 찾고 있습니다. 이 둘 중 하나만 가능하다면, 나는 더 적은 시간을 선호합니다. 이상적인 솔루션은 |
으로 분리 된 항목이 더 많은 문자열과 <>
이 완전히없는 문자열에도 사용할 수 있습니다. 적어도 정규 표현식 기반 솔루션
내 이해 (당신은 기본적으로 두 가지 결과 목록, |
및 <>
에 분할 두 번째로 분할 하나를 얻을 수 있기 때문에) split()
더 많은 메모리를 사용하는 것이 될 것이라고 할 것이나, RegEx가 어떻게 수행 할 것인지를 판단하기 위해 정규 표현식을 Python이 구현 한 것에 대해 충분히 알지 못합니다. split()
도 다른 수의 항목과 두 번째 분리 자의 부재로 인해 정상적인 표현보다 동적이지 않습니다.
- 예 내가 할 수있는, 단지 벤치 마크 두 솔루션,하지만 난 : 아직도, 나는 파이썬 정규식없이이 더 잘 할 수 있다는 인상을 흔들 수 없다, 내가
일부 메모를 요구하고 이유입니다 일반적으로 파이썬에 대해 뭔가 배우려고하고 어떻게 작동하는지, 그리고 내가이 두 가지를 벤치마킹한다면, 나는 아직도 파이썬 함수가 무엇을 놓쳤는 지 모릅니다.
- 그렇습니다.이 수준에서 최적화하는 것은 고성능 물건에만 꼭 필요한 것이지만 제가 말했던 것처럼 저는 파이썬에 대해 배우려고합니다.
- 추가 : 원래의 질문에, 나는 완전히 내가합니다 (구분자
<>
와 부품에서|
로 구분 된 부분,re.split(\||<>,input)
에 의해 생성 된 매우 간단한 단순 목록을 구별 할 수 있어야한다는 얘기를 깜빡 했네요 @obmarg가 제안한대로) 너무 잘 작동하지 않을 것이다. 이 기준에 부합하는 솔루션은 높이 평가됩니다.
질문의 요약 : 어떤 이유로 가장 효율적인 해결책이 될까요?
import timeit
import re
def splitit(input):
res0 = input.split("|")
res = []
for element in res0:
t = element.split("<>")
if t != [element]:
res0.remove(element)
res.append(t)
return (res0, res)
def regexit(input):
return re.split("\||<>", input)
def mgibsonbr(input): # Solution by @mgibsonbr
items = re.split(r'\||<>', input) # Split input in items
offset = 0
result = [] # The result: strings for regular itens, lists for <> separated ones
acc = None
for i in items:
delimiter = '|' if offset+len(i) < len(input) and input[offset+len(i)] == '|' else '<>'
offset += len(i) + len(delimiter)
if delimiter == '<>': # Will always put the item in a list
if acc is None:
acc = [i] # Create one if doesn't exist
result.append(acc)
else:
acc.append(i)
else:
if acc is not None: # If there was a list, put the last item in it
acc.append(i)
else:
result.append(i) # Add the regular items
acc = None # Clear the list, since what will come next is a regular item or a new list
return result
def split2(input): # Solution by @duncan
res0 = input.split("|")
res1, res2 = [], []
for r in res0:
if "<>" in r:
res2.append(r.split("<>"))
else:
res1.append(r)
return res1, res2
print "mgibs:", timeit.Timer("mgibsonbr('a|b|c|de|f<>ge<>ah')","from __main__ import mgibsonbr").timeit()
print "split:", timeit.Timer("splitit('a|b|c|de|f<>ge<>ah')","from __main__ import splitit").timeit()
print "split2:", timeit.Timer("split2('a|b|c|de|f<>ge<>ah')","from __main__ import split2").timeit()
print "regex:", timeit.Timer("regexit('a|b|c|de|f<>ge<>ah')","from __main__ import regexit").timeit()
print "mgibs:", timeit.Timer("mgibsonbr('a|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>ah')","from __main__ import mgibsonbr").timeit()
print "split:", timeit.Timer("splitit('a|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>ah')","from __main__ import splitit").timeit()
print "split:", timeit.Timer("split2('a|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>ah')","from __main__ import split2").timeit()
print "regex:", timeit.Timer("regexit('a|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>aha|b|c|de|f<>ge<>ah')","from __main__ import regexit").timeit()
결과 :
때문에 여러 요청에, 나는 split()
-solution에 대한 몇 가지 timeit 및 @obmarg에 의해 처음 제안 된 정규 표현식뿐만 아니라 @mgibsonbr 및 @duncan으로 솔루션을 실행 한 : 죄송합니다 (
mgibs: 14.7349407408
split: 6.403942732
split2: 3.68306812233
regex: 5.28414318792
mgibs: 107.046683735
split: 46.0844590775
split2: 26.5595985591
regex: 28.6513302646
, 그것은 (적어도이 제한된 데이터 세트로) 길이에 관계없이, 모든 다른 알고리즘을 친다 @duncan에 의해 split2처럼 보인다, 또한 @ mgibsonbr의 솔루션은 몇 가지 성능 문제가 같습니다 'bout that, b ut 솔루션에 관계없이).
모두에게 감사드립니다.
가 이동, 그냥'timeit'를 사용하고 직접 참조하십시오. 그것은 간단합니다. 내 베팅은'str.split'에 있습니다. – wim
긴 문자열의 경우 '재'가 더 빠를 것이라고 생각합니다. 하지만 반드시 벤치마킹해야합니다. – Dikei
나는 이것이 IO 경계 일 것이라고 확신한다. 내 첫 번째 추측은 모든 유형의 분할이 디스크 또는 네트워크에서받는 입력보다 빠르다는 것입니다. –