Python-剖析其所有后缀的“域”

时间:2018-07-29 06:57:23

标签: python

在给定格式为{a.b.c.d等的域中,strings之间的'.' is > 1数是什么?他的后缀列表,按最长的后缀排序,降序排列。

例如,给定www.hello.com,我想要以下输出:

['www.hello.com', 'hello.com', 'com']

2 个答案:

答案 0 :(得分:3)

这应该有效:

s = 'www.hello.com'
splits = s.split('.')
['.'.join(splits[i:]) for i in range(len(splits))]
# ['www.hello.com', 'hello.com', 'com']

我不确定这是否是最佳选择,但第一件事出现在我的脑海中。

答案 1 :(得分:2)

如果您使用split参数'.'上的字符串,则最后一个元素将是后缀:

maxsplit

因此,您只需要获取每个拆分的最后一个元素:

>>> domain = 'www.hello.com'
>>> domain.split('.', 0)
['www.hello.com']
>>> domain.split('.', 1)
['www', 'hello.com']
>>> domain.split('.', 2)
['www', 'hello', 'com']

这是“ 非常理想”吗?我不知道。相当快:

>>> [domain.split('.', i)[-1] for i in range(domain.count('.')+1)]
['www.hello.com', 'hello.com', 'com']

Arman's solution相比,由于In [259]: %timeit [domain.split('.', i)[-1] for i in range(domain.count('.')+1 2.43 µs ± 121 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 的成本,我希望会有一个小的常数因数差异,但我们不做猜测,而是进行测试:

join

所以,是的,它慢了约55%(实际上比我预期的还快),但在这里,我们所说的是微秒。


我们可以更快地提出一些建议吗?也许吧,但是会更加冗长。我们正在整个字符串上反复调用In [261]: s = domain In [262]: %timeit ['.'.join(s.split('.')[i:]) for i in range(len(s.split('.')))] 3.79 µs ± 119 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 。如果我们仅split一次并split次多次该怎么办?我怀疑join会更快一点,因为它不涉及搜索,直到您找到足够大的字符串(分配速度更快)为止,但是同样,让我们​​不要猜测,让我们测试一下:

join

嗯,节省了20纳秒。


从技术上讲,这两种解决方案都具有二次复杂性。

我们可以在线性时间内做到吗?

首先,如果我们只得到In [264]: %timeit parts=domain.split('.'); ['.'.join(parts[i:]) for i in range(len(pats))] 2.41 µs ± 86.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 的位置并进行切片怎么办?那实际上仍然是二次时间,因为每个切片仍然是线性时间操作,即使它比.split快得多。

但是我们在Python中所做的 在这里肯定是二次的。我们必须创建N个新字符串,其平均长度是N的倍,这意味着将分配和复制join个字符。

如果我们可以得到一个新的字符串对象,该对象引用与N*N相同的字符串缓冲区…那么,您不能在Python中做到这一点,但是理论上可以在C语言中做到这一点。但是首先,让我们看看是否看起来值得做:

domain[pos:]

这是比较麻烦的时间,但是需要7.02µs。所有这些额外的工作以及所有这些额外的pos = 0 dots = [] while True: dots.append(pos) pos = domain.find('.', pos) if pos == -1: break pos += 1 [domain[pos:] for pos in dots] 浪费的时间比我们节省的时间要多得多。也许如果您有大量的组件,那值得,但是只需三个?我对此表示怀疑。

即使不共享字符串缓冲区,用C编写此逻辑也可能比使用ifsplit更快,然后诱使Python在该共享缓冲区周围构造字符串对象可能节省更多时间…但是,除非这2微秒确实是代码中的瓶颈,否则您真的要在这里编写C扩展吗? (而且,您必须非常小心地使用它们-字符串对象希望拥有其存储空间,并且您不希望拆分删除它们不拥有的缓冲区…)


如果您确实需要提高速度,因为您的字符串是纯ASCII,则可以使用join来节省更多时间。 (然后您甚至可以bytes使用它来避免复制切片,但是这样做的代价是无法memoryview做它们,而无需执行额外的步骤……)当然,字节的使用不太方便,如果您可以使用人类可读的Unicode代替IDNA punycode,就可以使用IDNA域,那么它将根本无法工作...