Мой текущий проект Python потребует много разделения строк для обработки входящих пакетов. Поскольку я буду запускать его на довольно медленной системе, мне было интересно, какой самый эффективный способ сделать это. Строки будут отформатированы примерно так:
Item 1 | Item 2 | Item 3 <> Item 4 <> Item 5
Объяснение: Этот конкретный пример будет получен из списка, в котором первые два элемента являются заголовком и датой, тогда как пункт 3 - пункт 5 будут приглашены людям (число может быть любым от нуля до n, где n это количество зарегистрированных пользователей на сервере).
Из того, что я вижу, у меня есть следующие опции:
- многократно используйте
split()
- Используйте регулярное выражение и функции регулярных выражений
- Некоторые другие функции Python, о которых я еще не думал (возможно, некоторые из них)
Решение 1 будет включать разделение в |
, а затем разбиение последнего элемента результирующего списка на <>
для этого примера, тогда как решение 2, вероятно, приведет к регулярному выражению, например:
((.+)|)+((.+)(<>)?)+
Хорошо, этот RegEx ужасен, я сам это вижу. Он также непроверен. Но у вас есть идея.
Теперь я ищу способ, которым a) занимает наименьшее количество времени и б) идеально использует наименьший объем памяти. Если возможно только одно из двух, я бы предпочел меньше времени. Идеальное решение также будет работать для строк, у которых больше элементов разделено с |
и строками, которым полностью не хватает <>
. По крайней мере, решение, основанное на регулярном выражении, сделало бы это
Мое понимание было бы в том, что split()
будет использовать больше памяти (так как вы в основном получаете два результирующих списка, разделяемых на |
, а второй - на <>
), но я недостаточно знаю о реализации регулярных выражений Pythons, чтобы судить о том, как RegEx будет выполнять. split()
также менее динамичен, чем регулярное выражение, если оно имеет значение для разных чисел элементов и отсутствия второго разделителя. Тем не менее, я не могу поколебать впечатление, что python может сделать это лучше без регулярных выражений, поэтому я прошу
Некоторые примечания:
- Да, я мог бы просто проверить оба решения, но я пытаюсь узнать что-то о питоне вообще и о том, как он работает здесь, и если я просто сравниваю эти два, я до сих пор не знаю, какие функции python я пропустил.
- Да, оптимизация на этом уровне действительно нужна только для высокопроизводительных вещей, но, как я уже сказал, я пытаюсь узнать о python.
- Добавление: в исходном вопросе, я совершенно забыл упомянуть, что мне нужно различать части, разделенные
|
от частей с помощью разделителя<>
, поэтому простой плоский список, созданныйre.split(\||<>,input)
(как было предложено @obmarg), не будет работать слишком хорошо. Решения, соответствующие этому критерию, очень ценятся.
Подводя вопрос: какое решение было бы наиболее эффективным, по каким причинам.
Из-за нескольких запросов я запустил некоторое время на split()
-решении и первом предложенном регулярном выражении by @obmarg, а также решениях @mgibsonbr и @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()
Результаты:
mgibs: 14.7349407408
split: 6.403942732
split2: 3.68306812233
regex: 5.28414318792
mgibs: 107.046683735
split: 46.0844590775
split2: 26.5595985591
regex: 28.6513302646
На данный момент похоже, что split2 by @duncan превосходит все остальные алгоритмы, независимо от длины (с этим ограниченным набором данных, по крайней мере), а также выглядит так: решение @mgibsonbr имеет некоторые проблемы с производительностью (извините, но, но спасибо за решение независимо).
Спасибо за ввод, все.