Python 检查列表A是否包含列表B中某项的前缀

Python 检查列表A是否包含列表B中某项的前缀,python,python-3.x,for-loop,Python,Python 3.x,For Loop,我有两个列表,我们可以称之为A和B。我需要检查列表A中的项目,查看B中的项目是否以A中的项目开始,然后停止检查 A中的内容示例: https://some/path http://another/path http://another.some/path B中的内容示例: http://another/path http://this/wont/match/anything 目前我正在这样做: def check_comps(self, comps): for a in self.A:

我有两个列表,我们可以称之为
A
B
。我需要检查列表
A
中的项目,查看
B
中的项目是否以
A
中的项目开始,然后停止检查

A中的内容示例:

https://some/path
http://another/path
http://another.some/path
B中的内容示例:

http://another/path
http://this/wont/match/anything
目前我正在这样做:

def check_comps(self, comps):
   for a in self.A:
      for b in comps:
         if b.startswith(a):
            return a

有更好的方法吗?

您的解决方案具有最坏情况下的O(nm)时间复杂度,即如果n~m,则为O(n^2)。您可以很容易地将其简化为O(n log(n))甚至O(log(n))。这里是如何

考虑一个单词列表(你的
comps
attrubute)和一个目标(你的
b

注意,通过按字典顺序对单词列表进行排序,可以得到前缀列表

prefixes = ['abc', 'abcabc', 'abd', 'abdc', 'acb']
它是退化的,因为
前缀[0]
前缀[1]
的前缀,因此所有以
前缀[1]
开头的东西同样以
前缀[0]
开头。这有点问题。让我们看看原因。让我们使用快速(二进制)搜索在
前缀
列表中找到目标的正确位置

import bisect


bisect.bisect(prefixes, target)  #  -> 2
这是因为
target
prefixes[1]
共享一个前缀,但
target[3]>prefixes[1][3]
,因此从词典编纂的角度来看,它应该使用前缀。因此,如果在
前缀
中有
目标
的前缀,则它应该位于索引
2
的左侧。显然,
目标
不是以
前缀[1]
开头的,因此在最坏的情况下,我们必须一直搜索左侧,以确定是否有前缀。现在请注意,如果我们将这些
前缀
转换为非退化列表,则目标的唯一可能前缀将始终位于
bisect.bisect
返回的位置的左侧。让我们减少前缀列表,并编写一个helper函数来检查是否有目标的前缀

from functools import reduce


def minimize_prefixes(prefixes):
    """
    Note! `prefixes` must be sorted lexicographically !
    """
    def accum_prefs(prefixes, prefix):
        if not prefix.startswith(prefixes[-1]):
            return prefixes.append(prefix) or prefixes
        return prefixes
    prefs_iter = iter(prefixes)
    return reduce(accum_prefs, prefs_iter, [next(prefs_iter)]) if prefixes else []


def hasprefix(minimized_prefixes, target):
    position = bisect.bisect(minimized_prefixes, target)
    return target.startswith(minimized_prefixes[position-1]) if position else False
现在让我们看看

min_prefixes = minimize_prefixes(prefixes)
print(min_prefixes)  # -> ['abc', 'abd', 'acb']
hasprefix(min_prefixes, target)  # -> True
让我们做一个必须失败的测试:

min_prefs_fail = ["abcde"]
hasprefix(min_prefs_fail, target)  # -> False

这样就得到了O(nlog(n))搜索,它比O(n^2)解渐进地快。注意!您可以(而且确实应该)将
minimize_前缀(排序(comps))
前缀集存储为对象中的一个属性,使任何前缀搜索都成为O(log(n)),这比您现在的搜索速度还要快

@MosesKoledoye,这不管用。我正在尝试查看B中的内容是否与A中的内容开始匹配。我不寻找完全匹配的内容。您所获得的将起作用,但是。。。。。它还将识别字符串
b
位于字符串“a”中但不一定在开头的匹配项。您可能希望导入
re',并使用
if re.match(b,a):`作为触发a返回的测试条件
re.match
只在字符串的biging处匹配内容。@R.Sharp我知道它会起作用,我正在尝试找出是否有更好更有效的方法this@free_mind检查这是否符合您的要求:
{i for i in A for j in comps if j.startswith(i)}
OP提供的示例不是最好的,因为返回的项目实际上是相同的。类似于
B
的目录和
A
的子目录会更好。
min_prefs_fail = ["abcde"]
hasprefix(min_prefs_fail, target)  # -> False