Python 从列表中删除作为列表中其他字符串项前缀的所有字符串项

Python 从列表中删除作为列表中其他字符串项前缀的所有字符串项,python,algorithm,prefix-tree,Python,Algorithm,Prefix Tree,我有一个路径列表,我只想保留那些不是任何其他项目前缀的项目 例如,在以下列表中: private private/etc private/etc/pam.d usr usr/local usr/local/lib usr/local/lib/security 我只想保留: private/etc/pam.d usr/local/lib/security 我不喜欢“发明轮子”和实现前缀树,而是使用已经实现了这一点的python包 谢谢 如果您的列表已排序,则每个项目都是以下项目的前缀或不是以下

我有一个路径列表,我只想保留那些不是任何其他项目前缀的项目

例如,在以下列表中:

private
private/etc
private/etc/pam.d
usr
usr/local
usr/local/lib
usr/local/lib/security
我只想保留:

private/etc/pam.d
usr/local/lib/security
我不喜欢“发明轮子”和实现前缀树,而是使用已经实现了这一点的python包


谢谢

如果您的列表已排序,则每个项目都是以下项目的前缀或不是以下任何项目的前缀

因此,你可以写:

ls.sort()
[ls[i] for i in range(len(ls))[:-1] if ls[i] != ls[i+1][:len(ls[i])]] + [ls[-1]]
另一个实现,使用zip:

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

我不知道有什么包,但这应该可以:

#a is the list of items
for i in range(len(a)):
    for j in range(i, len(a)):
        if (a[i] in a[j]) and len(a[i]) < len(a[j]):
            a[i] = 'delete'

a = [i for i in a if i!= 'delete'] #new list without prefixed elements
#a是项目列表
对于范围内的i(len(a)):
对于范围(i,len(a))内的j:
如果(a[i]在a[j]中)和len(a[i])
我觉得这可以通过使用子字符串来解决,也就是说,您要查找的字符串不是任何其他字符串的子字符串

这里有一个java解决方案,您可以在python中使用相同的逻辑

public static void findFullyQualifiedPaths() {

    List<String> paths = new ArrayList<>();
    paths.add("private");
    paths.add("private/etc");
    paths.add("private/etc/pam.d");
    paths.add("usr");
    paths.add("usr/local");
    paths.add("usr/local/lib");
    paths.add("usr/local/lib/security");

    System.out.println("Input Paths");
    System.out.println(paths);

    List<String> filteredPaths = new ArrayList<String>(paths);

    filteredPaths.removeIf(currentPath -> {
        for (String path : paths) {
            if ((!path.equals(currentPath)) && path.contains(currentPath)) {
                return true;
            }
        }
        return false;
    });
    System.out.println("Paths after removing the substrings");
    System.out.println(filteredPaths);
}

或者一个字符串包含另一个字符串但不是前缀的情况如何,例如
private/etc/pam.d
fooprivate/etc/pam.d
。另外,如果列表中的
private/etc/pam.d
位于
private
之前,我认为这不起作用。如果输入中有一个值为
'delete'
@Oli的字符串,那又该怎么办呢?我必须承认,我不知道这些问题的答案。对于第一个,您可以检查它是否只在字符串的前半部分,对于第二个,您可以用delete替换一些随机字符串。如果你有一个更有效的解决方案,请分享,我真的对如何改进很感兴趣如果我对你的代码做最小的修改,我会使用
a[I].startswith(a[j])
来解决第一个问题(这个方法已经存在,也可以使用它!)。要解决第二个问题,请将范围(len(a)):中j的第二个for循环更改为
,并使用if语句防止将列表项与其自身进行比较。要防止用“delete”替换项,最安全的选择是使用大小相同的第二个列表来标记是否应删除或保留第一个列表中的每个项目:声明列表
keep_item=[True for i in range(len(a))]
如果a[i]:startswith(a[j]):keep_item[j]=False
,然后
a=[item for item,keep in zip(a,keep_item),如果keep]
Input Paths
[private, private/etc, private/etc/pam.d, usr, usr/local, usr/local/lib, usr/local/lib/security]
Paths after removing the substrings
[private/etc/pam.d, usr/local/lib/security]