Python 类似项目的检查表
给出以下列表Python 类似项目的检查表,python,list,Python,List,给出以下列表 simple_list = ['abcX1', 'def', 'abc', 'abcX2', 'abcY', 'defX1', 'efg', 'fgh'] 如何删除起始相同但没有后缀的项目 例如: 关于'abcX1',abc',abcX2',abcY'我只想保留'abcX1',abcX2',abcY' 关于'def','defX1'我想保留'defX1' 对于“efg”、“fgh”,我想保留两者,因为它们没有带后缀的对应项 我的想法: for i in simple_list
simple_list = ['abcX1', 'def', 'abc', 'abcX2', 'abcY', 'defX1', 'efg', 'fgh']
如何删除起始相同但没有后缀的项目
例如:
- 关于
我只想保留'abcX1',abc',abcX2',abcY'
'abcX1',abcX2',abcY'
- 关于
我想保留'def','defX1'
'defX1'
- 对于“efg”、“fgh”,我想保留两者,因为它们没有带后缀的对应项
for i in simple_list:
for j in simple_list:
Here I am stuck
此外,我的尝试似乎不太像蟒蛇。因此,我们非常感谢您的建议。尝试以下方法:
filtered_list = [x for x in simple_list if not any([y.startswith(x) and y != x for y in simple_list])]
对于短列表,您可以将嵌套列表理解与
any
一起使用,检查当前元素是否是任何其他元素(自身除外)的前缀
如果列表包含重复元素,则保留所有重复项;在这种情况下,您应该比较索引而不是元素本身,或者首先从元素创建一个集合。)
但是,请注意,这将具有二次复杂性,即O(n²),这对于较长的列表可能是禁止的。更好(但也有点复杂)的方法是从所有单词中创建一个Trie或前缀树,然后只使用该树的叶子
tree = {}
for w in lst:
t = tree
for c in w:
t = t.setdefault(c, {})
def leafs(t, p=""):
return [x for k in t for x in leafs(t[k], p+k)] if t else [p]
res = list(leafs(tree))
创建树和获取叶子的复杂度应该是O(n*k),其中n是单词数,k是每个单词中的平均字母数。1
另一种方法更简单:请注意,如果x
是y
的前缀,那么x
将在y
之前排序,因此您可以对列表进行排序,然后只需比较连续的值。排序的复杂度为O(n logn),然后过滤的复杂度为O(n)
srt = sorted(lst)
res = [x for i, x in enumerate(srt)
if i == len(srt) - 1 or not srt[i+1].startswith(x)]
树和排序方法都可能扰乱结果中元素的顺序。如果希望元素按其原始顺序排列,可以从过滤的元素创建一个集
,然后在原始列表上进行另一次传递,保留集中的元素。这将添加另一个O(n):
每种方式的结果res
都是['abcX1','abcX2','abcY','defX1','efg','fgh']
。此外,它们都将创建一个新的过滤列表,但不会修改原始列表
我做了更多的时间分析。对于您的列表,正如预期的那样,没有太大的差异。有趣的是,前缀树最慢,可能是因为创建所有这些字典的开销超过了短列表中的O(n²)。分拣速度最快
>>> %timeit test.simple(lst)
10000 loops, best of 5: 44.3 µs per loop
>>> %timeit test.prefixtree(lst)
10000 loops, best of 5: 51.6 µs per loop
>>> %timeit test.sorting(lst)
100000 loops, best of 5: 11.2 µs per loop
更重要的是,在1000个单词的列表中,前缀树(现在比嵌套循环快得多)仍然比排序慢得多,尽管其复杂性较低。我对这一点的解释是,内置sorted
的O(n logn)是用快速C实现的,而树的O(n)仍然是慢速Python
>>> %timeit test.simple(words)
1 loop, best of 5: 562 ms per loop
>>> %timeit test.prefixtree(words)
100 loops, best of 5: 8.42 ms per loop
>>> %timeit test.sorting(words)
1000 loops, best of 5: 1.23 ms per loop
1我在这里添加了k因子,因为它在这个算法中更为明显,但当然,使用
startswith
也不是O(1),而是O([实际前缀的长度])请用您尝试过的一些实际代码更新您的问题,这些代码不起作用。是否有固定长度(如3)必须删除的元素中的一个,或者它们可以是任意长度的,甚至可以是1?您只需要用实际的代码替换上面描述的delete
,这取决于列表的大小,如果列表相对较小,请使用goodvibration的解决方案。通过构建树,有更快的算法。defX1
将被保留,但在这种情况下,defX12
将被删除
>>> %timeit test.simple(lst)
10000 loops, best of 5: 44.3 µs per loop
>>> %timeit test.prefixtree(lst)
10000 loops, best of 5: 51.6 µs per loop
>>> %timeit test.sorting(lst)
100000 loops, best of 5: 11.2 µs per loop
>>> %timeit test.simple(words)
1 loop, best of 5: 562 ms per loop
>>> %timeit test.prefixtree(words)
100 loops, best of 5: 8.42 ms per loop
>>> %timeit test.sorting(words)
1000 loops, best of 5: 1.23 ms per loop