Каков наиболее эффективный способ объединить две строки и удалить все перед первым ',' в Python? - PullRequest
6 голосов
/ 06 ноября 2010

В Python у меня есть строка, представляющая собой список значений, разделенных запятыми.например, '5,2,7,8,3,4'

Мне нужно добавить новое значение в конец и удалить первое значение,

например, '5,22,7,814,3,4 '-> '22, 7,814,3,4,1'

В настоящее время я делаю это следующим образом:

mystr = '5,22,7,814,3,4'
latestValue='1'
mylist = mystr.split(',')
mystr = ''
for i in range(len(mylist)-1):
   if i==0:
      mystr += mylist[i+1]
   if i>0:
      mystr += ','+mylist[i+1]

mystr += ','+latestValue

Это выполняется миллион раз в моем кодеЯ определил, что это узкое место, поэтому я стремлюсь оптимизировать его, чтобы он работал быстрее.

Что наиболее эффективно для этого (с точки зрения времени выполнения)?

Ответы [ 6 ]

9 голосов
/ 06 ноября 2010

Используйте это:

if mystr == '':
    mystr = latestValue
else:
    mystr = mystr[mystr.find(",")+1:] + "," + latestValue

Это должно быть намного быстрее, чем любое решение, которое разбивает список.Он находит только первое вхождение , и «удаляет» начало строки.Кроме того, если список пуст, то mystr будет просто latestValue (незначительные накладные расходы, добавленные этим) - спасибо Пауло Скардина за указание на это.

6 голосов
/ 06 ноября 2010
_, sep, rest = mystr.partition(",")
mystr = rest + sep + latestValue

Это также работает без изменений, если mystr пусто или один элемент (без запятой после него) из-за str.partition возвращает пустое sepесли в mystr.

нет sep. Вы можете использовать mystr.rstrip(",") перед вызовом partition(), если в mystr.

может быть запятая.
6 голосов
/ 06 ноября 2010
mystr = mystr.partition(",")[2]+","+latestValue

улучшение, предложенное Пауло для работы, если mystr имеет <2 элемента. <br>В случае 0 элементов, оно расширяет mystr для хранения одного элемента.

_,_,mystr = (mystr+','+latestValue).partition(',')

$ python -m timeit -s "mystr = '5,22,7,814,3,4';latestValue='1'" "mystr[mystr.find(',')+1:]+','+latestValue"
1000000 loops, best of 3: 0.847 usec per loop
$ python -m timeit -s "mystr = '5,22,7,814,3,4';latestValue='1'" "mystr = mystr.partition(',')[2]+','+latestValue"
1000000 loops, best of 3: 0.703 usec per loop
4 голосов
/ 06 ноября 2010

лучшая версия : ответ гнибблера


Поскольку вам нужна скорость (миллионы раз много), я профилировал.Этот примерно в два раза быстрее, чем разделить список:

i = 0
while 1:
    if mystr[i] == ',': break
    i += 1
mystr = mystr[i+1:] + ', ' + latest_value

Предполагается, что после запятой стоит один пробел.Если это проблема, вы можете использовать:

i = 0
while 1:
    if mystr[i] == ',': break
    i += 1
mystr = mystr[i+1:].strip() + ', ' + latest_value

, который лишь немного медленнее, чем оригинал, но гораздо более устойчивый.Вам решать, с какой скоростью вам нужно выжать.Они оба предполагают, что в строке будет запятая, и в случае невозможности ее появления поднимут IndexError.Безопасная версия:

i = 0
while 1:
    try:
        if mystr[i] == ',': break
    except IndexError:
        i = -1
        break
    i += 1
mystr = mystr[i+1:].strip() + ', ' + latest_value

Опять же, это все еще значительно быстрее, чем разделение строки, но добавляет надежности за счет скорости.


Вот время, которое это приводит.Вы можете видеть, что четвертый метод заметно быстрее, чем третий (самый надежный) метод, но немного медленнее, чем первые два метода.Это самое быстрое из двух надежных решений, хотя, если вы не уверены, что в ваших строках будут запятые (т. Е. Если бы их не было, это уже считалось бы ошибкой), то я все равно использовал бы его.

$ python -mtimeit -s 'из тестов импорта строк, method1' 'method1 (tests [0], "10")' 1000000 циклов, лучшее из 3: 1,34 usec на цикл

$ python -mtimeit -s'from strings import tests, method2' 'method2 (tests [0], "10")' 1000000 циклов, лучше всего 3: 1,34 usec на цикл

$ python -mtimeit -s'из тестов импорта строк,method3 '' method3 (tests [0], "10") '1000000 циклов, лучшее из 3: 1,5 usec на цикл

$ python -mtimeit -s'из строк импортировать тесты, method4' 'method4 (тесты[0], "10") '1000000 циклов, лучшее из 3: 1,38 usec на цикл


$ python -mtimeit -s'из тестов импорта строк, method5' 'method5 (tests [0], "10") '100000 циклов, лучшее из 3: 1,18 usec на цикл

Это ответ Гнибблера

2 голосов
/ 06 ноября 2010

Отредактировано: Не самый лучший, но я люблю однострочники. : -)

mystr = ','.join(mystr.split(',')[1:]+[latestValue])

Перед тестированием я бы поспорил, что он будет работать лучше.

> python -m timeit "mystr = '5,22,7,814,3,4'" "latestValue='1'" \
"mylist = mystr.split(',')" "mylist.append(latestValue);" \
"mystr = ','.join(mylist[1:])"
1000000 loops, best of 3: 1.37 usec per loop
> python -m timeit "mystr = '5,22,7,814,3,4'" "latestValue='1'"\
"','.join(mystr.split(',')[1:]+[latestValue])"
1000000 loops, best of 3: 1.5 usec per loop
> python -m timeit "mystr = '5,22,7,814,3,4'" "latestValue='1'"\
'mystr=mystr[mystr.find(",")+1:]+","+latestValue'
1000000 loops, best of 3: 0.625 usec per loop
2 голосов
/ 06 ноября 2010
mylist = mystr.split(',')
mylist.append(latestValue);
mystr = ",".join(mylist[1:])

Конкатенация строк в python не очень эффективна (поскольку строки неизменяемы).С ними проще работать в виде списков (и более эффективно).По сути, в своем коде вы копируете свою строку снова и снова каждый раз, когда присоединяетесь к ней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...