Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类似项目的检查表_Python_List - Fatal编程技术网

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