Dự án Python hiện tại của tôi sẽ yêu cầu nhiều phân tách chuỗi để xử lý các gói đến. Vì tôi sẽ chạy nó trên một hệ thống khá chậm, tôi đã tự hỏi cách hiệu quả nhất để thực hiện điều này là gì. Các chuỗi sẽ được định dạng một cái gì đó như thế này:Cách hiệu quả nhất để tách các chuỗi trong Python
Item 1 | Item 2 | Item 3 <> Item 4 <> Item 5
Giải thích: ví dụ cụ thể này sẽ đến từ một danh sách nơi hai mục đầu tiên là một tiêu đề và một ngày, trong khi khoản 3 đến khoản 5 sẽ được mời người (The số lượng có thể là từ 0 đến n, trong đó n là số lượng người dùng đã đăng ký trên máy chủ).
Từ những gì tôi thấy, tôi có các tùy chọn sau:
- nhiều lần sử dụng
split()
- Sử dụng một biểu thức chính quy và Regex chức năng
- Một số chức năng Python khác tôi đã không nghĩ về chưa (Có có lẽ một số)
Giải pháp 1 sẽ bao gồm chia tách tại |
và sau đó chia phần tử cuối cùng của danh sách kết quả tại <>
ví dụ này, trong khi giải pháp 2 có lẽ sẽ cho kết quả trong một biểu thức chính quy như:
((.+)|)+((.+)(<>)?)+
Okay, RegEx này là khủng khiếp, tôi có thể thấy rằng bản thân mình. Nó cũng chưa được kiểm tra. Nhưng bạn hiểu ý rồi đấy.
Bây giờ, tôi đang tìm cách mà a) mất ít thời gian nhất và b) lý tưởng sử dụng lượng bộ nhớ ít nhất. Nếu chỉ có một trong hai là có thể, tôi sẽ thích ít thời gian hơn. Giải pháp lý tưởng cũng sẽ hoạt động đối với các chuỗi có nhiều mục hơn được phân tách bằng |
và các chuỗi hoàn toàn thiếu <>
. Ít nhất là Giải pháp biểu dựa trên thường xuyên sẽ làm điều đó
hiểu biết của tôi sẽ là split()
sẽ sử dụng nhiều bộ nhớ hơn (vì bạn về cơ bản có được hai danh sách kết quả, một trong những chia tại |
và điều thứ hai để tách tại <>
), nhưng Tôi không biết đủ về việc thực hiện các biểu thức chính quy của Pythons để đánh giá RegEx sẽ thực hiện như thế nào. split()
cũng kém năng động hơn so với cụm từ thông dụng nếu nó hiển thị với số lượng mục khác nhau và sự vắng mặt của seperator thứ hai. Tuy nhiên, tôi không thể lắc ấn tượng rằng trăn có thể làm điều này tốt hơn mà không biểu thức thông thường, đó là lý do tại sao tôi yêu cầu
Một số lưu ý:
- Vâng, tôi có thể chỉ benchmark cả hai giải pháp, nhưng tôi cố gắng tìm hiểu một cái gì đó về python nói chung và cách nó hoạt động ở đây, và nếu tôi chỉ là điểm chuẩn hai, tôi vẫn không biết những gì python chức năng tôi đã bỏ qua.
- Có, tối ưu hóa ở cấp độ này chỉ thực sự cần thiết cho các công cụ hiệu suất cao, nhưng như tôi đã nói, tôi đang cố gắng tìm hiểu mọi thứ về python.
- Addition: trong câu hỏi ban đầu, tôi hoàn toàn quên đề cập đến mà tôi cần để có thể phân biệt các bộ phận được tách bởi
|
từ các bộ phận với seperator<>
, do đó, một danh sách đơn giản bằng phẳng như được tạo ra bởire.split(\||<>,input)
(theo đề xuất của @obmarg) sẽ không hoạt động tốt. Các giải pháp phù hợp tiêu chí này được nhiều người đánh giá cao.
Để tổng hợp câu hỏi: Giải pháp nào là giải pháp hiệu quả nhất, vì lý do gì.
Do nhiều yêu cầu, tôi đã chạy một số timeit trên split()
-solution và đề xuất biểu thức chính quy đầu tiên của @obmarg, cũng như các giải pháp bởi @mgibsonbr và @duncan:
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()
Kết quả :
mgibs: 14.7349407408
split: 6.403942732
split2: 3.68306812233
regex: 5.28414318792
mgibs: 107.046683735
split: 46.0844590775
split2: 26.5595985591
regex: 28.6513302646
tại thời điểm này, có vẻ như split2 bởi @duncan nhịp đập tất cả các thuật toán khác, bất kể chiều dài (với bộ dữ liệu hạn chế này ít nhất), và nó cũng giống như @ mgibsonbr của giải pháp có một số vấn đề hiệu suất (Xin lỗi 'bout rằng, b ut cảm ơn cho giải pháp bất kể).
Cảm ơn bạn đã nhập, mọi người.
Đi trên, chỉ cần sử dụng 'timeit' và xem cho chính mình. Dễ thôi. Cược của tôi là 'str.split'. – wim
Tôi nghĩ chuỗi dài, 're' có thể nhanh hơn. Nhưng bạn phải chuẩn bị để chắc chắn. – Dikei
Tôi muốn đặt cược rằng đây là IO bị ràng buộc. Dự đoán đầu tiên của tôi là nói rằng bất kỳ loại chia tách nào sẽ nhanh hơn loại đầu vào nhận được từ đĩa hoặc mạng. –