当前位置: 代码迷 >> python >> Python:从列表中删除哪些元素是其他元素的前缀
  详细解决方案

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

热度:22   发布时间:2023-07-16 09:39:42.0

最快(&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不等。

列表理解( 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(尽管如果要将它用于大型列表,缩放更重要)

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

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我们

如果您的列表最初是无序的,则首先执行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