Python:从列表中删除哪些元素是其他元素的前缀

时间:2014-03-14 03:22:26

标签: python

最快(& python)方式获取不包含任何其他元素作为其前缀的元素列表。

(元素可以是任何顺序,为了清楚起见,解释元素在这里保持顺序,所以如果需要排序必须明确地进行)

输入

['AB', 'ABC', 'ABCDEF', 'ABCDEFG', 'BCD', 'DEF', 'DEFGHI', 'EF', 'GKL', 'JKLM']

消除了元素:

'AB' prefix of 'ABC'
'ABC' prefix of 'ABCDEF'
'ABCDEF' prefix OF 'ABCDEFG'
'DEF' prefix of 'DEFGHI'

预期产出

['ABCDEFG', 'BCD', 'DEFGHI', 'EF', 'GKL', 'JKLM']

被修改

增加一点复杂性(或清晰度)。列表的平均长度从500到900不等。

3 个答案:

答案 0 :(得分:1)

列表理解(ls是输入列表的名称):

[x for x in ls if x not in [y[:len(x)] for y in ls if y != x]]

我怀疑它在性能方面是最快的,但这个想法非常简单。您将逐个元素地遍历list,并检查它是否是所有其余元素列表中任何元素的前缀。

timeit结果:每循环11.9 us(尽管如果你打算将它用于大型列表,缩放更重要)

答案 1 :(得分:1)

如果您的列表已排序,则每个元素都是下一个元素的前缀,或者不是任何元素的前缀。因此,您可以写:

ls.sort()
[ls[i] for i in range(len(ls))[:-1] if ls[i] != ls[i+1][:len(ls[i])]] + [ls[-1]]

这将是n log(n)排序加上一次通过列表(n)。

对于您当前的排序列表,它也稍微快一些,因为它是线性的,timeit给出2.11 us。

使用zip稍微快一点(但不是渐近),也更加pythonic:

[x for x, y in zip(ls[:-1], ls[1:]) if x != y[:len(x)]] + [ls[-1]]

timeit给出1.77我们

答案 2 :(得分:0)

如果您的列表最初是无序的,请先

ls.sort()

使用startswith

In [71]: [i for i, j in zip(ls[:-1], ls[1:]) if not j.startswith(i)]+[ls[-1]]
Out[71]: ['ABCDEFG', 'BCD', 'DEFGHI', 'EF', 'GKL', 'JKLM']

enumerate

[v for i, v in enumerate(ls[:-1]) if not ls[i+1].startswith(v)]+[ls[-1]]

与@ sashkello的方法相比:

In [78]: timeit [v for i, v in enumerate(ls[:-1]) if not ls[i+1].startswith(v)]+[ls[-1]] 
10000 loops, best of 3: 29.6 us per loop

In [79]: timeit [i for i, j in zip(ls[:-1], ls[1:]) if not j.startswith(i)]+[ls[-1]]
10000 loops, best of 3: 28.5 us per loop

In [80]: timeit [x for x in ls if x not in [y[:len(x)] for y in ls if y != x]]
1000 loops, best of 3: 1.77 ms per loop