在字符串中重复删除连续字符的最快方法 - Python

时间:2017-02-14 01:54:53

标签: python string unicode duplicates

我们可以使用以下符号对字符串中的连续字符进行重复数据删除:

def deduplicate(string, char):
    return char.join([substring for substring in string.strip().split(char) if substring])

E.g。

>>> s = 'this is   an   irritating string with  random spacing  .'
>>> deduplicate(s)
'this is an irritating string with random spacing .'

在命令行中,squeeze有一个tr选项:

$ tr -s " " < file

Python的字符串中是否有squeeze函数?

在Python中对字符串中的连续字符进行重复数据删除的最快方法是什么?

请注意,要进行重复数据删除的字符应该是任何ascii / unicode字符,而不仅仅是\s / whitespace。 (ascii和unicode有2个子答案,这很好。

2 个答案:

答案 0 :(得分:3)

Itertools是一个很好的尝试

>>> t = "THHHISSS ISSS BBBBSSSSS"
>>> import itertools
>>> ''.join(char for char, _ in itertools.groupby(t))
'THIS IS BS'

答案 1 :(得分:2)

首先,您的deduplicate功能实际上非常快。但是可以进行一些改进以使其更快。我lambda了你的功能并将其称为org_deduplicate(下方)。现在进行一些时间测试(使用iPython&#39; s %timeit):

s = 'this is   an   irritating string with  random spacing  .'

org_deduplicate = lambda s,c: c.join([substring for substring in s.strip().split(c) if substring])

%timeit org_deduplicate(s,' ')
100000 loops, best of 3: 3.59 µs per loop

strip确实不是必需的,甚至可能会给你带来意想不到的结果(如果你没有重复数据删除空格),我们可以试试:

org_deduplicate2 = lambda s,c: c.join(substring for substring in s.split(c) if substring)

%timeit org_deduplicate2(s,' ')
100000 loops, best of 3: 3.4 µs per loop

它可以加快速度,但并不是那么令人印象深刻。让我们尝试一种不同的方法......正则表达式。这些也很好,因为它们可以灵活地选择任何正则表达式作为你的#34;字符&#34;重复数据删除(不只是一个字符):

import re

re_deduplicate = lambda s,c: re.sub(r'(%s)(?:\1)+' %c, '\g<1>',  s)
re_deduplicate2 = lambda s,c: c.join(re.split('%s+'%c,s))

%timeit re_deduplicate(s,' ')
100000 loops, best of 3: 13.8 µs per loop

%timeit re_deduplicate2(s,' ')
100000 loops, best of 3: 6.47 µs per loop

第二个更快,但都不接近你原来的功能。看起来常规字符串操作比re函数更快。如果我们尝试压缩(如果使用Python 2,则使用itertools.izip)该怎么办:

zip_deduplicate = lambda s,c: ''.join(s1 for s1,s2 in zip(s,s[1:]) if s1!=c or s1!=s2)

%timeit zip_deduplicate(s,' ')
100000 loops, best of 3: 12.9 µs per loop

仍然没有改善。 zip方法会产生太多的子串,这使得''.join变慢。好的再试一次...... str.replace递归调用:

def rec_deduplicate(s,c):                                                                             
    if s.find(c*2) != -1:   
        return rec_deduplicate(s.replace(c*2, c),c)
    return s

%timeit rec_deduplicate(s,' ')
100000 loops, best of 3: 2.83 µs per loop

不错,这似乎是我们的赢家。但是,可以肯定的是,让我们用一个非常长的输入字符串来反对我们的原始函数:

s2 = s*100000

%timeit rec_deduplicate(s2,' ')
10 loops, best of 3: 64.6 ms per loop

%timeit org_deduplicate(s2,' ')
1 loop, best of 3: 209 ms per loop
是的,它看起来很好地缩放。但是让我们再尝试一次测试,递归重复数据删除器只在每次调用时删除长度为2的重复字符。因此,使用长重复字符仍可以做得更好:

s3 = 'this is                       an                        irritating string with                                  random spacing  .'

%timeit rec_deduplicate(s3,' ')
100000 loops, best of 3: 9.93 µs per loop

%timeit org_deduplicate(s3,' ')
100000 loops, best of 3: 8.99 µs per loop

当要删除多个重复字符串时,它确实失去了一些优势。

总之,如果您的字符串具有重复字符的长子串,请使用您的原始函数(可能会进行一些调整)。否则,递归版本最快。